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

Commit 22dc3b7b authored by Esteban Talavera's avatar Esteban Talavera Committed by Alexandra Gherghina
Browse files

New AccountManager method to copy accounts between users.

Adding the copyAccountToUser method which copies an account
along with its credentials to a different user.

Also an extra in the public api to identify the account to migrate
during provisioning.

Bug: 17716971
Change-Id: I2f29f1765ba0d360a3894b13ef86253b7c7d3284
parent f39cec0b
Loading
Loading
Loading
Loading
+34 −0
Original line number Diff line number Diff line
@@ -1442,6 +1442,40 @@ public class AccountManager {
        }
    }

    /**
     * Copies an account from the primary user to another user.
     * @param account the account to copy
     * @param user the target user
     * @param callback Callback to invoke when the request completes,
     *     null for no callback
     * @param handler {@link Handler} identifying the callback thread,
     *     null for the main thread
     * @return An {@link AccountManagerFuture} which resolves to a Boolean indicated wether it
     * succeeded.
     * @hide
     */
    public AccountManagerFuture<Boolean> copyAccountToUser(
            final Account account, final UserHandle user,
            AccountManagerCallback<Boolean> callback, Handler handler) {
        if (account == null) throw new IllegalArgumentException("account is null");
        if (user == null) throw new IllegalArgumentException("user is null");

        return new Future2Task<Boolean>(handler, callback) {
            @Override
            public void doWork() throws RemoteException {
                mService.copyAccountToUser(
                        mResponse, account, UserHandle.USER_OWNER, user.getIdentifier());
            }
            @Override
            public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
                if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
                    throw new AuthenticatorException("no result in response");
                }
                return bundle.getBoolean(KEY_BOOLEAN_RESULT);
            }
        }.start();
    }

    /**
     * @hide
     * Removes the shared account.
+2 −0
Original line number Diff line number Diff line
@@ -42,6 +42,8 @@ interface IAccountManager {
    void removeAccountAsUser(in IAccountManagerResponse response, in Account account,
        boolean expectActivityLaunch, int userId);
    boolean removeAccountExplicitly(in Account account);
    void copyAccountToUser(in IAccountManagerResponse response, in Account account,
        int userFrom, int userTo);
    void invalidateAuthToken(String accountType, String authToken);
    String peekAuthToken(in Account account, String authTokenType);
    void setAuthToken(in Account account, String authTokenType, String authToken);
+34 −29
Original line number Diff line number Diff line
@@ -486,7 +486,7 @@ public class AccountManagerService
        for (Account sa : sharedAccounts) {
            if (ArrayUtils.contains(accounts, sa)) continue;
            // Account doesn't exist. Copy it now.
            copyAccountToUser(sa, UserHandle.USER_OWNER, userId);
            copyAccountToUser(null /*no response*/, sa, UserHandle.USER_OWNER, userId);
        }
    }

@@ -672,16 +672,31 @@ public class AccountManagerService
        }
    }

    private boolean copyAccountToUser(final Account account, int userFrom, int userTo) {
    @Override
    public void copyAccountToUser(final IAccountManagerResponse response, final Account account,
            int userFrom, int userTo) {
        enforceCrossUserPermission(UserHandle.USER_ALL, "Calling copyAccountToUser requires "
                    + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
        final UserAccounts fromAccounts = getUserAccounts(userFrom);
        final UserAccounts toAccounts = getUserAccounts(userTo);
        if (fromAccounts == null || toAccounts == null) {
            return false;
            if (response != null) {
                Bundle result = new Bundle();
                result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
                try {
                    response.onResult(result);
                } catch (RemoteException e) {
                    Slog.w(TAG, "Failed to report error back to the client." + e);
                }
            }
            return;
        }

        Slog.d(TAG, "Copying account " + account.name
                + " from user " + userFrom + " to user " + userTo);
        long identityToken = clearCallingIdentity();
        try {
            new Session(fromAccounts, null, account.type, false,
            new Session(fromAccounts, response, account.type, false,
                    false /* stripAuthTokenFromResult */) {
                @Override
                protected String toDebugString(long now) {
@@ -696,12 +711,10 @@ public class AccountManagerService

                @Override
                public void onResult(Bundle result) {
                    if (result != null) {
                        if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
                    if (result != null
                            && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
                        // Create a Session for the target user and pass in the bundle
                            completeCloningAccount(result, account, toAccounts);
                        }
                        return;
                        completeCloningAccount(response, result, account, toAccounts);
                    } else {
                        super.onResult(result);
                    }
@@ -710,14 +723,13 @@ public class AccountManagerService
        } finally {
            restoreCallingIdentity(identityToken);
        }
        return true;
    }

    void completeCloningAccount(final Bundle result, final Account account,
            final UserAccounts targetUser) {
    private void completeCloningAccount(IAccountManagerResponse response,
            final Bundle accountCredentials, final Account account, final UserAccounts targetUser) {
        long id = clearCallingIdentity();
        try {
            new Session(targetUser, null, account.type, false,
            new Session(targetUser, response, account.type, false,
                    false /* stripAuthTokenFromResult */) {
                @Override
                protected String toDebugString(long now) {
@@ -730,10 +742,10 @@ public class AccountManagerService
                    // Confirm that the owner's account still exists before this step.
                    UserAccounts owner = getUserAccounts(UserHandle.USER_OWNER);
                    synchronized (owner.cacheLock) {
                        Account[] ownerAccounts = getAccounts(UserHandle.USER_OWNER);
                        for (Account acc : ownerAccounts) {
                        for (Account acc : getAccounts(UserHandle.USER_OWNER)) {
                            if (acc.equals(account)) {
                                mAuthenticator.addAccountFromCredentials(this, account, result);
                                mAuthenticator.addAccountFromCredentials(
                                        this, account, accountCredentials);
                                break;
                            }
                        }
@@ -742,18 +754,11 @@ public class AccountManagerService

                @Override
                public void onResult(Bundle result) {
                    if (result != null) {
                        if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
                            // TODO: Anything?
                        } else {
                            // TODO: Show error notification
                            // TODO: Should we remove the shadow account to avoid retries?
                        }
                        return;
                    } else {
                    // TODO: Anything to do if if succedded?
                    // TODO: If it failed: Show error notification? Should we remove the shadow
                    // account to avoid retries?
                    super.onResult(result);
                }
                }

                @Override
                public void onError(int errorCode, String errorMessage) {
@@ -2740,7 +2745,7 @@ public class AccountManagerService
                    break;

                case MESSAGE_COPY_SHARED_ACCOUNT:
                    copyAccountToUser((Account) msg.obj, msg.arg1, msg.arg2);
                    copyAccountToUser(/*no response*/ null, (Account) msg.obj, msg.arg1, msg.arg2);
                    break;

                default: