diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index e6b7a4c287cd4..b059cc7e2aa2d 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -2977,19 +2977,21 @@ public class AccountManagerService * outside of those expected to be injected by the AccountManager, e.g. * ANDORID_PACKAGE_NAME. */ - String token = readCachedTokenInternal( + TokenCache.Value cachedToken = readCachedTokenInternal( accounts, account, authTokenType, callerPkg, callerPkgSigDigest); - if (token != null) { + if (cachedToken != null) { logGetAuthTokenMetrics(callerPkg, account.type); if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "getAuthToken: cache hit ofr custom token authenticator."); } Bundle result = new Bundle(); - result.putString(AccountManager.KEY_AUTHTOKEN, token); + result.putString(AccountManager.KEY_AUTHTOKEN, cachedToken.token); + result.putLong(AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, + cachedToken.expiryEpochMillis); result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type); onResult(response, result); @@ -6121,7 +6123,7 @@ public class AccountManagerService } } - protected String readCachedTokenInternal( + protected TokenCache.Value readCachedTokenInternal( UserAccounts accounts, Account account, String tokenType, diff --git a/services/core/java/com/android/server/accounts/TokenCache.java b/services/core/java/com/android/server/accounts/TokenCache.java index 66e550fe3c4cf..9427ee41cfdcf 100644 --- a/services/core/java/com/android/server/accounts/TokenCache.java +++ b/services/core/java/com/android/server/accounts/TokenCache.java @@ -20,8 +20,6 @@ import android.accounts.Account; import android.util.LruCache; import android.util.Pair; -import com.android.internal.util.Preconditions; - import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -35,7 +33,8 @@ import java.util.Objects; private static final int MAX_CACHE_CHARS = 64000; - private static class Value { + /** Package private*/ + static class Value { public final String token; public final long expiryEpochMillis; @@ -217,12 +216,12 @@ import java.util.Objects; /** * Gets a token from the cache if possible. */ - public String get(Account account, String tokenType, String packageName, byte[] sigDigest) { + public Value get(Account account, String tokenType, String packageName, byte[] sigDigest) { Key k = new Key(account, tokenType, packageName, sigDigest); Value v = mCachedTokens.get(k); long currentTime = System.currentTimeMillis(); if (v != null && currentTime < v.expiryEpochMillis) { - return v.token; + return v; } else if (v != null) { remove(account.type, v.token); } diff --git a/services/tests/servicestests/res/xml/test_account_type1_authenticator.xml b/services/tests/servicestests/res/xml/test_account_type1_authenticator.xml index 0c531de1827e8..a4558acdc274c 100644 --- a/services/tests/servicestests/res/xml/test_account_type1_authenticator.xml +++ b/services/tests/servicestests/res/xml/test_account_type1_authenticator.xml @@ -18,4 +18,5 @@ android:accountType="@string/test_account_type1" android:icon="@drawable/icon1" android:smallIcon="@drawable/icon1" + android:customTokens="true" android:label="@string/test_account_type1_authenticator_label" /> diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java index 997a138cf58f0..d5c5745d6680f 100644 --- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java @@ -26,9 +26,11 @@ import static org.mockito.Matchers.eq; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.never; import static org.mockito.Mockito.nullable; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.accounts.AbstractAccountAuthenticator; import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.AccountManagerInternal; @@ -1698,13 +1700,14 @@ public class AccountManagerServiceTest extends AndroidTestCase { final CountDownLatch latch = new CountDownLatch(1); Response response = new Response(latch, mMockAccountManagerResponse); + long expiryEpochTimeInMillis = System.currentTimeMillis() + ONE_DAY_IN_MILLISECOND; mAms.getAuthToken( response, // response AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, "authTokenType", // authTokenType true, // notifyOnAuthFailure false, // expectActivityLaunch - createGetAuthTokenOptions()); + createGetAuthTokenOptionsWithExpiry(expiryEpochTimeInMillis)); waitForLatch(latch); verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture()); @@ -1715,6 +1718,58 @@ public class AccountManagerServiceTest extends AndroidTestCase { AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS); assertEquals(result.getString(AccountManager.KEY_ACCOUNT_TYPE), AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1); + assertEquals(result.getLong(AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY), + expiryEpochTimeInMillis); + } + + @SmallTest + public void testGetAuthTokenCachedSuccess() throws Exception { + unlockSystemUser(); + when(mMockContext.createPackageContextAsUser( + anyString(), anyInt(), any(UserHandle.class))).thenReturn(mMockContext); + when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager); + String[] list = new String[]{AccountManagerServiceTestFixtures.CALLER_PACKAGE}; + when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(list); + + final CountDownLatch latch = new CountDownLatch(1); + Response response = new Response(latch, mMockAccountManagerResponse); + long expiryEpochTimeInMillis = System.currentTimeMillis() + ONE_DAY_IN_MILLISECOND; + mAms.getAuthToken( + response, // response + AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, + "authTokenType", // authTokenType + true, // notifyOnAuthFailure + false, // expectActivityLaunch + createGetAuthTokenOptionsWithExpiry(expiryEpochTimeInMillis)); + waitForLatch(latch); + + // Make call for cached token. + mAms.getAuthToken( + response, // response + AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, + "authTokenType", // authTokenType + true, // notifyOnAuthFailure + false, // expectActivityLaunch + createGetAuthTokenOptionsWithExpiry(expiryEpochTimeInMillis + 10)); + waitForLatch(latch); + + verify(mMockAccountManagerResponse, times(2)).onResult(mBundleCaptor.capture()); + List result = mBundleCaptor.getAllValues(); + assertGetTokenResponse(result.get(0), expiryEpochTimeInMillis); + // cached token was returned with the same expiration time as first token. + assertGetTokenResponse(result.get(1), expiryEpochTimeInMillis); + } + + private void assertGetTokenResponse(Bundle result, long expiryEpochTimeInMillis) { + assertEquals(result.getString(AccountManager.KEY_AUTHTOKEN), + AccountManagerServiceTestFixtures.AUTH_TOKEN); + assertEquals(result.getString(AccountManager.KEY_ACCOUNT_NAME), + AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS); + assertEquals(result.getString(AccountManager.KEY_ACCOUNT_TYPE), + AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1); + assertEquals(result.getLong(AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY), + expiryEpochTimeInMillis); + } @SmallTest @@ -3241,11 +3296,16 @@ public class AccountManagerServiceTest extends AndroidTestCase { } private Bundle createGetAuthTokenOptions() { + return createGetAuthTokenOptionsWithExpiry( + System.currentTimeMillis() + ONE_DAY_IN_MILLISECOND); + } + + private Bundle createGetAuthTokenOptionsWithExpiry(long expiryEpochTimeInMillis) { Bundle options = new Bundle(); options.putString(AccountManager.KEY_ANDROID_PACKAGE_NAME, AccountManagerServiceTestFixtures.CALLER_PACKAGE); options.putLong(AccountManagerServiceTestFixtures.KEY_TOKEN_EXPIRY, - System.currentTimeMillis() + ONE_DAY_IN_MILLISECOND); + expiryEpochTimeInMillis); return options; }