Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2ed6369c authored by Carlos Valdivia's avatar Carlos Valdivia Committed by Android (Google) Code Review
Browse files

Merge "System Health: Support expiring tokens" into mnc-dev

parents bb0e5391 91979be8
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -2716,6 +2716,7 @@ package android.accounts {
    method public final android.os.IBinder getIBinder();
    method public final android.os.IBinder getIBinder();
    method public abstract android.os.Bundle hasFeatures(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String[]) throws android.accounts.NetworkErrorException;
    method public abstract android.os.Bundle hasFeatures(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String[]) throws android.accounts.NetworkErrorException;
    method public abstract android.os.Bundle updateCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
    method public abstract android.os.Bundle updateCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
    field public static final java.lang.String KEY_CUSTOM_TOKEN_EXPIRY = "android.accounts.expiry";
  }
  }
  public class Account implements android.os.Parcelable {
  public class Account implements android.os.Parcelable {
+1 −0
Original line number Original line Diff line number Diff line
@@ -2797,6 +2797,7 @@ package android.accounts {
    method public final android.os.IBinder getIBinder();
    method public final android.os.IBinder getIBinder();
    method public abstract android.os.Bundle hasFeatures(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String[]) throws android.accounts.NetworkErrorException;
    method public abstract android.os.Bundle hasFeatures(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String[]) throws android.accounts.NetworkErrorException;
    method public abstract android.os.Bundle updateCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
    method public abstract android.os.Bundle updateCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
    field public static final java.lang.String KEY_CUSTOM_TOKEN_EXPIRY = "android.accounts.expiry";
  }
  }
  public class Account implements android.os.Parcelable {
  public class Account implements android.os.Parcelable {
+51 −10
Original line number Original line Diff line number Diff line
@@ -108,6 +108,14 @@ import java.util.Arrays;
public abstract class AbstractAccountAuthenticator {
public abstract class AbstractAccountAuthenticator {
    private static final String TAG = "AccountAuthenticator";
    private static final String TAG = "AccountAuthenticator";


    /**
     * Bundle key used for the {@code long} expiration time (in millis from the unix epoch) of the
     * associated auth token.
     *
     * @see #getAuthToken
     */
    public static final String KEY_CUSTOM_TOKEN_EXPIRY = "android.accounts.expiry";

    private final Context mContext;
    private final Context mContext;


    public AbstractAccountAuthenticator(Context context) {
    public AbstractAccountAuthenticator(Context context) {
@@ -115,6 +123,7 @@ public abstract class AbstractAccountAuthenticator {
    }
    }


    private class Transport extends IAccountAuthenticator.Stub {
    private class Transport extends IAccountAuthenticator.Stub {
        @Override
        public void addAccount(IAccountAuthenticatorResponse response, String accountType,
        public void addAccount(IAccountAuthenticatorResponse response, String accountType,
                String authTokenType, String[] features, Bundle options)
                String authTokenType, String[] features, Bundle options)
                throws RemoteException {
                throws RemoteException {
@@ -140,6 +149,7 @@ public abstract class AbstractAccountAuthenticator {
            }
            }
        }
        }


        @Override
        public void confirmCredentials(IAccountAuthenticatorResponse response,
        public void confirmCredentials(IAccountAuthenticatorResponse response,
                Account account, Bundle options) throws RemoteException {
                Account account, Bundle options) throws RemoteException {
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -162,6 +172,7 @@ public abstract class AbstractAccountAuthenticator {
            }
            }
        }
        }


        @Override
        public void getAuthTokenLabel(IAccountAuthenticatorResponse response,
        public void getAuthTokenLabel(IAccountAuthenticatorResponse response,
                String authTokenType)
                String authTokenType)
                throws RemoteException {
                throws RemoteException {
@@ -184,6 +195,7 @@ public abstract class AbstractAccountAuthenticator {
            }
            }
        }
        }


        @Override
        public void getAuthToken(IAccountAuthenticatorResponse response,
        public void getAuthToken(IAccountAuthenticatorResponse response,
                Account account, String authTokenType, Bundle loginOptions)
                Account account, String authTokenType, Bundle loginOptions)
                throws RemoteException {
                throws RemoteException {
@@ -209,6 +221,7 @@ public abstract class AbstractAccountAuthenticator {
            }
            }
        }
        }


        @Override
        public void updateCredentials(IAccountAuthenticatorResponse response, Account account,
        public void updateCredentials(IAccountAuthenticatorResponse response, Account account,
                String authTokenType, Bundle loginOptions) throws RemoteException {
                String authTokenType, Bundle loginOptions) throws RemoteException {
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -234,6 +247,7 @@ public abstract class AbstractAccountAuthenticator {
            }
            }
        }
        }


        @Override
        public void editProperties(IAccountAuthenticatorResponse response,
        public void editProperties(IAccountAuthenticatorResponse response,
                String accountType) throws RemoteException {
                String accountType) throws RemoteException {
            checkBinderPermission();
            checkBinderPermission();
@@ -248,6 +262,7 @@ public abstract class AbstractAccountAuthenticator {
            }
            }
        }
        }


        @Override
        public void hasFeatures(IAccountAuthenticatorResponse response,
        public void hasFeatures(IAccountAuthenticatorResponse response,
                Account account, String[] features) throws RemoteException {
                Account account, String[] features) throws RemoteException {
            checkBinderPermission();
            checkBinderPermission();
@@ -262,6 +277,7 @@ public abstract class AbstractAccountAuthenticator {
            }
            }
        }
        }


        @Override
        public void getAccountRemovalAllowed(IAccountAuthenticatorResponse response,
        public void getAccountRemovalAllowed(IAccountAuthenticatorResponse response,
                Account account) throws RemoteException {
                Account account) throws RemoteException {
            checkBinderPermission();
            checkBinderPermission();
@@ -276,6 +292,7 @@ public abstract class AbstractAccountAuthenticator {
            }
            }
        }
        }


        @Override
        public void getAccountCredentialsForCloning(IAccountAuthenticatorResponse response,
        public void getAccountCredentialsForCloning(IAccountAuthenticatorResponse response,
                Account account) throws RemoteException {
                Account account) throws RemoteException {
            checkBinderPermission();
            checkBinderPermission();
@@ -291,6 +308,7 @@ public abstract class AbstractAccountAuthenticator {
            }
            }
        }
        }


        @Override
        public void addAccountFromCredentials(IAccountAuthenticatorResponse response,
        public void addAccountFromCredentials(IAccountAuthenticatorResponse response,
                Account account,
                Account account,
                Bundle accountCredentials) throws RemoteException {
                Bundle accountCredentials) throws RemoteException {
@@ -410,21 +428,42 @@ public abstract class AbstractAccountAuthenticator {
    public abstract Bundle confirmCredentials(AccountAuthenticatorResponse response,
    public abstract Bundle confirmCredentials(AccountAuthenticatorResponse response,
            Account account, Bundle options)
            Account account, Bundle options)
            throws NetworkErrorException;
            throws NetworkErrorException;

    /**
    /**
     * Gets the authtoken for an account.
     * Gets an authtoken for an account.
     *
     * If not {@code null}, the resultant {@link Bundle} will contain different sets of keys
     * depending on whether a token was successfully issued and, if not, whether one
     * could be issued via some {@link android.app.Activity}.
     * <p>
     * If a token cannot be provided without some additional activity, the Bundle should contain
     * {@link AccountManager#KEY_INTENT} with an associated {@link Intent}. On the other hand, if
     * there is no such activity, then a Bundle containing
     * {@link AccountManager#KEY_ERROR_CODE} and {@link AccountManager#KEY_ERROR_MESSAGE} should be
     * returned.
     * <p>
     * If a token can be successfully issued, the implementation should return the
     * {@link AccountManager#KEY_ACCOUNT_NAME} and {@link AccountManager#KEY_ACCOUNT_TYPE} of the
     * account associated with the token as well as the {@link AccountManager#KEY_AUTHTOKEN}. In
     * addition {@link AbstractAccountAuthenticator} implementations that declare themselves
     * {@code android:customTokens=true} may also provide a non-negative {@link
     * #KEY_CUSTOM_TOKEN_EXPIRY} long value containing the expiration timestamp of the expiration
     * time (in millis since the unix epoch).
     * <p>
     * Implementers should assume that tokens will be cached on the basis of account and
     * authTokenType. The system may ignore the contents of the supplied options Bundle when
     * determining to re-use a cached token. Furthermore, implementers should assume a supplied
     * expiration time will be treated as non-binding advice.
     * <p>
     * Finally, note that for android:customTokens=false authenticators, tokens are cached
     * indefinitely until some client calls {@link
     * AccountManager#invalidateAuthToken(String,String)}.
     *
     * @param response to send the result back to the AccountManager, will never be null
     * @param response to send the result back to the AccountManager, will never be null
     * @param account the account whose credentials are to be retrieved, will never be null
     * @param account the account whose credentials are to be retrieved, will never be null
     * @param authTokenType the type of auth token to retrieve, will never be null
     * @param authTokenType the type of auth token to retrieve, will never be null
     * @param options a Bundle of authenticator-specific options, may be null
     * @param options a Bundle of authenticator-specific options, may be null
     * @return a Bundle result or null if the result is to be returned via the response. The result
     * @return a Bundle result or null if the result is to be returned via the response.
     * will contain either:
     * <ul>
     * <li> {@link AccountManager#KEY_INTENT}, or
     * <li> {@link AccountManager#KEY_ACCOUNT_NAME}, {@link AccountManager#KEY_ACCOUNT_TYPE},
     * and {@link AccountManager#KEY_AUTHTOKEN}, or
     * <li> {@link AccountManager#KEY_ERROR_CODE} and {@link AccountManager#KEY_ERROR_MESSAGE} to
     * indicate an error
     * </ul>
     * @throws NetworkErrorException if the authenticator could not honor the request due to a
     * @throws NetworkErrorException if the authenticator could not honor the request due to a
     * network error
     * network error
     */
     */
@@ -518,6 +557,7 @@ public abstract class AbstractAccountAuthenticator {
    public Bundle getAccountCredentialsForCloning(final AccountAuthenticatorResponse response,
    public Bundle getAccountCredentialsForCloning(final AccountAuthenticatorResponse response,
            final Account account) throws NetworkErrorException {
            final Account account) throws NetworkErrorException {
        new Thread(new Runnable() {
        new Thread(new Runnable() {
            @Override
            public void run() {
            public void run() {
                Bundle result = new Bundle();
                Bundle result = new Bundle();
                result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
                result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
@@ -543,6 +583,7 @@ public abstract class AbstractAccountAuthenticator {
            Account account,
            Account account,
            Bundle accountCredentials) throws NetworkErrorException {
            Bundle accountCredentials) throws NetworkErrorException {
        new Thread(new Runnable() {
        new Thread(new Runnable() {
            @Override
            public void run() {
            public void run() {
                Bundle result = new Bundle();
                Bundle result = new Bundle();
                result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
                result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
+182 −21
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.accounts;
package com.android.server.accounts;


import android.Manifest;
import android.Manifest;
import android.accounts.AbstractAccountAuthenticator;
import android.accounts.Account;
import android.accounts.Account;
import android.accounts.AccountAndUser;
import android.accounts.AccountAndUser;
import android.accounts.AccountAuthenticatorResponse;
import android.accounts.AccountAuthenticatorResponse;
@@ -49,6 +50,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.RegisteredServicesCache;
import android.content.pm.RegisteredServicesCache;
import android.content.pm.RegisteredServicesCacheListener;
import android.content.pm.RegisteredServicesCacheListener;
import android.content.pm.ResolveInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
import android.content.pm.UserInfo;
import android.content.pm.UserInfo;
import android.database.Cursor;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.DatabaseUtils;
@@ -84,6 +86,11 @@ import com.google.android.collect.Sets;
import java.io.File;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.Timestamp;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.ArrayList;
@@ -93,6 +100,7 @@ import java.util.Date;
import java.util.HashMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.List;
import java.util.Map;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicInteger;
@@ -166,6 +174,10 @@ public class AccountManagerService
    private static final String[] ACCOUNT_TYPE_COUNT_PROJECTION =
    private static final String[] ACCOUNT_TYPE_COUNT_PROJECTION =
            new String[] { ACCOUNTS_TYPE, ACCOUNTS_TYPE_COUNT};
            new String[] { ACCOUNTS_TYPE, ACCOUNTS_TYPE_COUNT};
    private static final Intent ACCOUNTS_CHANGED_INTENT;
    private static final Intent ACCOUNTS_CHANGED_INTENT;
    static {
        ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
        ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
    }


    private static final String COUNT_OF_MATCHING_GRANTS = ""
    private static final String COUNT_OF_MATCHING_GRANTS = ""
            + "SELECT COUNT(*) FROM " + TABLE_GRANTS + ", " + TABLE_ACCOUNTS
            + "SELECT COUNT(*) FROM " + TABLE_GRANTS + ", " + TABLE_ACCOUNTS
@@ -177,6 +189,7 @@ public class AccountManagerService


    private static final String SELECTION_AUTHTOKENS_BY_ACCOUNT =
    private static final String SELECTION_AUTHTOKENS_BY_ACCOUNT =
            AUTHTOKENS_ACCOUNTS_ID + "=(select _id FROM accounts WHERE name=? AND type=?)";
            AUTHTOKENS_ACCOUNTS_ID + "=(select _id FROM accounts WHERE name=? AND type=?)";

    private static final String[] COLUMNS_AUTHTOKENS_TYPE_AND_AUTHTOKEN = {AUTHTOKENS_TYPE,
    private static final String[] COLUMNS_AUTHTOKENS_TYPE_AND_AUTHTOKEN = {AUTHTOKENS_TYPE,
            AUTHTOKENS_AUTHTOKEN};
            AUTHTOKENS_AUTHTOKEN};


@@ -205,6 +218,10 @@ public class AccountManagerService
        /** protected by the {@link #cacheLock} */
        /** protected by the {@link #cacheLock} */
        private final HashMap<Account, HashMap<String, String>> authTokenCache =
        private final HashMap<Account, HashMap<String, String>> authTokenCache =
                new HashMap<Account, HashMap<String, String>>();
                new HashMap<Account, HashMap<String, String>>();

        /** protected by the {@link #cacheLock} */
        private final HashMap<Account, WeakReference<TokenCache>> accountTokenCaches = new HashMap<>();

        /**
        /**
         * protected by the {@link #cacheLock}
         * protected by the {@link #cacheLock}
         *
         *
@@ -237,12 +254,6 @@ public class AccountManagerService
            new AtomicReference<AccountManagerService>();
            new AtomicReference<AccountManagerService>();
    private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
    private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};


    static {
        ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
        ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
    }


    /**
    /**
     * This should only be called by system code. One should only call this after the service
     * This should only be called by system code. One should only call this after the service
     * has started.
     * has started.
@@ -425,6 +436,7 @@ public class AccountManagerService
                        final Account account = new Account(accountName, accountType);
                        final Account account = new Account(accountName, accountType);
                        accounts.userDataCache.remove(account);
                        accounts.userDataCache.remove(account);
                        accounts.authTokenCache.remove(account);
                        accounts.authTokenCache.remove(account);
                        accounts.accountTokenCaches.remove(account);
                    } else {
                    } else {
                        ArrayList<String> accountNames = accountNamesByType.get(accountType);
                        ArrayList<String> accountNames = accountNamesByType.get(accountType);
                        if (accountNames == null) {
                        if (accountNames == null) {
@@ -1337,9 +1349,10 @@ public class AccountManagerService


    @Override
    @Override
    public void invalidateAuthToken(String accountType, String authToken) {
    public void invalidateAuthToken(String accountType, String authToken) {
        int callerUid = Binder.getCallingUid();
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "invalidateAuthToken: accountType " + accountType
            Log.v(TAG, "invalidateAuthToken: accountType " + accountType
                    + ", caller's uid " + Binder.getCallingUid()
                    + ", caller's uid " + callerUid
                    + ", pid " + Binder.getCallingPid());
                    + ", pid " + Binder.getCallingPid());
        }
        }
        if (accountType == null) throw new IllegalArgumentException("accountType is null");
        if (accountType == null) throw new IllegalArgumentException("accountType is null");
@@ -1353,6 +1366,7 @@ public class AccountManagerService
                db.beginTransaction();
                db.beginTransaction();
                try {
                try {
                    invalidateAuthTokenLocked(accounts, db, accountType, authToken);
                    invalidateAuthTokenLocked(accounts, db, accountType, authToken);
                    invalidateCustomTokenLocked(accounts, accountType, authToken);
                    db.setTransactionSuccessful();
                    db.setTransactionSuccessful();
                } finally {
                } finally {
                    db.endTransaction();
                    db.endTransaction();
@@ -1363,6 +1377,26 @@ public class AccountManagerService
        }
        }
    }
    }


    private void invalidateCustomTokenLocked(
            UserAccounts accounts,
            String accountType,
            String authToken) {
        if (authToken == null || accountType == null) {
            return;
        }
        // Also wipe out cached token in memory.
        for (Account a : accounts.accountTokenCaches.keySet()) {
            if (a.type.equals(accountType)) {
                WeakReference<TokenCache> tokenCacheRef =
                        accounts.accountTokenCaches.get(a);
                TokenCache cache = null;
                if (tokenCacheRef != null && (cache = tokenCacheRef.get()) != null) {
                    cache.remove(authToken);
                }
            }
        }
    }

    private void invalidateAuthTokenLocked(UserAccounts accounts, SQLiteDatabase db,
    private void invalidateAuthTokenLocked(UserAccounts accounts, SQLiteDatabase db,
            String accountType, String authToken) {
            String accountType, String authToken) {
        if (authToken == null || accountType == null) {
        if (authToken == null || accountType == null) {
@@ -1385,14 +1419,41 @@ public class AccountManagerService
                String accountName = cursor.getString(1);
                String accountName = cursor.getString(1);
                String authTokenType = cursor.getString(2);
                String authTokenType = cursor.getString(2);
                db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ID + "=" + authTokenId, null);
                db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ID + "=" + authTokenId, null);
                writeAuthTokenIntoCacheLocked(accounts, db, new Account(accountName, accountType),
                writeAuthTokenIntoCacheLocked(
                        authTokenType, null);
                        accounts,
                        db,
                        new Account(accountName, accountType),
                        authTokenType,
                        null);
            }
            }
        } finally {
        } finally {
            cursor.close();
            cursor.close();
        }
        }
    }
    }


    private void saveCachedToken(
            UserAccounts accounts,
            Account account,
            String callerPkg,
            byte[] callerSigDigest,
            String tokenType,
            String token,
            long expiryMillis) {

        if (account == null || tokenType == null || callerPkg == null || callerSigDigest == null) {
            return;
        }
        cancelNotification(getSigninRequiredNotificationId(accounts, account),
                new UserHandle(accounts.userId));
        synchronized (accounts.cacheLock) {
            TokenCache cache = getTokenCacheForAccountLocked(accounts, account);
            if (cache != null) {
                cache.put(token, tokenType, callerPkg, callerSigDigest, expiryMillis);
            }
            return;
        }
    }

    private boolean saveAuthTokenToDatabase(UserAccounts accounts, Account account, String type,
    private boolean saveAuthTokenToDatabase(UserAccounts accounts, Account account, String type,
            String authToken) {
            String authToken) {
        if (account == null || type == null) {
        if (account == null || type == null) {
@@ -1510,6 +1571,7 @@ public class AccountManagerService
                    db.update(TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
                    db.update(TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
                    db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?", argsAccountId);
                    db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?", argsAccountId);
                    accounts.authTokenCache.remove(account);
                    accounts.authTokenCache.remove(account);
                    accounts.accountTokenCaches.remove(account);
                    db.setTransactionSuccessful();
                    db.setTransactionSuccessful();


                    String action = (password == null || password.length() == 0) ?
                    String action = (password == null || password.length() == 0) ?
@@ -1673,9 +1735,14 @@ public class AccountManagerService
    }
    }


    @Override
    @Override
    public void getAuthToken(IAccountManagerResponse response, final Account account,
    public void getAuthToken(
            final String authTokenType, final boolean notifyOnAuthFailure,
            IAccountManagerResponse response,
            final boolean expectActivityLaunch, Bundle loginOptionsIn) {
            final Account account,
            final String authTokenType,
            final boolean notifyOnAuthFailure,
            final boolean expectActivityLaunch,
            final Bundle loginOptions) {

        if (Log.isLoggable(TAG, Log.VERBOSE)) {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "getAuthToken: " + account
            Log.v(TAG, "getAuthToken: " + account
                    + ", response " + response
                    + ", response " + response
@@ -1707,6 +1774,7 @@ public class AccountManagerService
        final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
        final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
        authenticatorInfo = mAuthenticatorCache.getServiceInfo(
        authenticatorInfo = mAuthenticatorCache.getServiceInfo(
                AuthenticatorDescription.newKey(account.type), accounts.userId);
                AuthenticatorDescription.newKey(account.type), accounts.userId);

        final boolean customTokens =
        final boolean customTokens =
                authenticatorInfo != null && authenticatorInfo.type.customTokens;
                authenticatorInfo != null && authenticatorInfo.type.customTokens;


@@ -1715,11 +1783,24 @@ public class AccountManagerService
        final boolean permissionGranted = customTokens ||
        final boolean permissionGranted = customTokens ||
            permissionIsGranted(account, authTokenType, callerUid);
            permissionIsGranted(account, authTokenType, callerUid);


        final Bundle loginOptions = (loginOptionsIn == null) ? new Bundle() :
        // Get the calling package. We will use it for the purpose of caching.
            loginOptionsIn;
        final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
        List<String> callerOwnedPackageNames = Arrays.asList(mPackageManager.getPackagesForUid(callerUid));
        if (callerPkg == null || !callerOwnedPackageNames.contains(callerPkg)) {
            String msg = String.format(
                    "Uid %s is attempting to illegally masquerade as package %s!",
                    callerUid,
                    callerPkg);
            throw new SecurityException(msg);
        }

        // let authenticator know the identity of the caller
        // let authenticator know the identity of the caller
        loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
        loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
        loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
        loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());

        // Distill the caller's package signatures into a single digest.
        final byte[] callerPkgSigDigest = calculatePackageSignatureDigest(callerPkg);

        if (notifyOnAuthFailure) {
        if (notifyOnAuthFailure) {
            loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
            loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
        }
        }
@@ -1740,6 +1821,28 @@ public class AccountManagerService
                }
                }
            }
            }


            if (customTokens) {
                /*
                 * Look up tokens in the new cache only if the loginOptions don't have parameters
                 * outside of those expected to be injected by the AccountManager, e.g.
                 * ANDORID_PACKAGE_NAME.
                 */
                String token = readCachedTokenInternal(
                        accounts,
                        account,
                        authTokenType,
                        callerPkg,
                        callerPkgSigDigest);
                if (token != null) {
                    Bundle result = new Bundle();
                    result.putString(AccountManager.KEY_AUTHTOKEN, token);
                    result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
                    result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
                    onResult(response, result);
                    return;
                }
            }

            new Session(accounts, response, account.type, expectActivityLaunch,
            new Session(accounts, response, account.type, expectActivityLaunch,
                    false /* stripAuthTokenFromResult */, account.name,
                    false /* stripAuthTokenFromResult */, account.name,
                    false /* authDetailsRequired */) {
                    false /* authDetailsRequired */) {
@@ -1786,9 +1889,26 @@ public class AccountManagerService
                                        "the type and name should not be empty");
                                        "the type and name should not be empty");
                                return;
                                return;
                            }
                            }
                            Account resultAccount = new Account(name, type);
                            if (!customTokens) {
                            if (!customTokens) {
                                saveAuthTokenToDatabase(mAccounts, new Account(name, type),
                                saveAuthTokenToDatabase(
                                        authTokenType, authToken);
                                        mAccounts,
                                        resultAccount,
                                        authTokenType,
                                        authToken);
                            }
                            long expiryMillis = result.getLong(
                                    AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 0L);
                            if (customTokens
                                    && expiryMillis > System.currentTimeMillis()) {
                                saveCachedToken(
                                        mAccounts,
                                        account,
                                        callerPkg,
                                        callerPkgSigDigest,
                                        authTokenType,
                                        authToken,
                                        expiryMillis);
                            }
                            }
                        }
                        }


@@ -1807,6 +1927,25 @@ public class AccountManagerService
        }
        }
    }
    }


    private byte[] calculatePackageSignatureDigest(String callerPkg) {
        MessageDigest digester;
        try {
            digester = MessageDigest.getInstance("SHA-256");
            PackageInfo pkgInfo = mPackageManager.getPackageInfo(
                    callerPkg, PackageManager.GET_SIGNATURES);
            for (Signature sig : pkgInfo.signatures) {
                digester.update(sig.toByteArray());
            }
        } catch (NoSuchAlgorithmException x) {
            Log.wtf(TAG, "SHA-256 should be available", x);
            digester = null;
        } catch (NameNotFoundException e) {
            Log.w(TAG, "Could not find packageinfo for: " + callerPkg);
            digester = null;
        }
        return (digester == null) ? null : digester.digest();
    }

    private void createNoCredentialsPermissionNotification(Account account, Intent intent,
    private void createNoCredentialsPermissionNotification(Account account, Intent intent,
            int userId) {
            int userId) {
        int uid = intent.getIntExtra(
        int uid = intent.getIntExtra(
@@ -3398,7 +3537,6 @@ public class AccountManagerService
                return;
                return;
            }
            }
        }
        }

        String msg = "caller uid " + uid + " lacks any of " + TextUtils.join(",", permissions);
        String msg = "caller uid " + uid + " lacks any of " + TextUtils.join(",", permissions);
        Log.w(TAG, "  " + msg);
        Log.w(TAG, "  " + msg);
        throw new SecurityException(msg);
        throw new SecurityException(msg);
@@ -3796,6 +3934,18 @@ public class AccountManagerService
        }
        }
    }
    }


    protected String readCachedTokenInternal(
            UserAccounts accounts,
            Account account,
            String tokenType,
            String callingPackage,
            byte[] pkgSigDigest) {
        synchronized (accounts.cacheLock) {
            TokenCache cache = getTokenCacheForAccountLocked(accounts, account);
            return cache.get(tokenType, callingPackage, pkgSigDigest);
        }
    }

    protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts, final SQLiteDatabase db,
    protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts, final SQLiteDatabase db,
            Account account, String key, String value) {
            Account account, String key, String value) {
        HashMap<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
        HashMap<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
@@ -3877,6 +4027,17 @@ public class AccountManagerService
        return authTokensForAccount;
        return authTokensForAccount;
    }
    }


    protected TokenCache getTokenCacheForAccountLocked(UserAccounts accounts, Account account) {
        WeakReference<TokenCache> cacheRef = accounts.accountTokenCaches.get(account);
        TokenCache cache;
        if (cacheRef == null || (cache = cacheRef.get()) == null) {
            cache = new TokenCache();
            cacheRef = new WeakReference<>(cache);
            accounts.accountTokenCaches.put(account, cacheRef);
        }
        return cache;
    }

    private Context getContextForUser(UserHandle user) {
    private Context getContextForUser(UserHandle user) {
        try {
        try {
            return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
            return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
+163 −0

File added.

Preview size limit exceeded, changes collapsed.