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

Commit 67df64b3 authored by Amith Yamasani's avatar Amith Yamasani
Browse files

Shared accounts and sharing of apps

API and preliminary implementation for sharing primary user accounts with a secondary user.
AbstractAccountAuthenticator has new methods to retrieve and apply a bundle of credentials
to clone an account from the primary to a restricted secondary user. The AccountManagerService
initiates the account clone when it starts up the user and detects that the user has
a shared account registered that hasn't been converted to a real account.

AccountManager also has new hidden APIs to add/remove/get shared accounts. There might be
further improvements to this API to make shared accounts hidden/visible to select apps.

AccountManagerService has a new table to store the shared account information.

Added ability in PackageManager to install and uninstall packages for a secondary user. This
is required when the primary user selects a few apps to share with a restricted user.

Remove shared accounts from secondary users when primary user removes the account.

Change-Id: I9378ed0d8c1cc66baf150a4bec0ede56f6f8b06b
parent 0ffc81c1
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1094,7 +1094,7 @@ public final class Pm {
    private boolean deletePackage(String pkg, int unInstallFlags) {
        PackageDeleteObserver obs = new PackageDeleteObserver();
        try {
            mPm.deletePackage(pkg, obs, unInstallFlags);
            mPm.deletePackageAsUser(pkg, obs, UserHandle.USER_OWNER, unInstallFlags);

            synchronized (obs) {
                while (!obs.finished) {
+82 −0
Original line number Diff line number Diff line
@@ -275,6 +275,38 @@ public abstract class AbstractAccountAuthenticator {
                handleException(response, "getAccountRemovalAllowed", account.toString(), e);
            }
        }

        public void getAccountCredentialsForCloning(IAccountAuthenticatorResponse response,
                Account account) throws RemoteException {
            checkBinderPermission();
            try {
                final Bundle result =
                        AbstractAccountAuthenticator.this.getAccountCredentialsForCloning(
                                new AccountAuthenticatorResponse(response), account);
                if (result != null) {
                    response.onResult(result);
                }
            } catch (Exception e) {
                handleException(response, "getAccountCredentialsForCloning", account.toString(), e);
            }
        }

        public void addAccountFromCredentials(IAccountAuthenticatorResponse response,
                Account account,
                Bundle accountCredentials) throws RemoteException {
            checkBinderPermission();
            try {
                final Bundle result =
                        AbstractAccountAuthenticator.this.addAccountFromCredentials(
                                new AccountAuthenticatorResponse(response), account,
                                accountCredentials);
                if (result != null) {
                    response.onResult(result);
                }
            } catch (Exception e) {
                handleException(response, "addAccountFromCredentials", account.toString(), e);
            }
        }
    }

    private void handleException(IAccountAuthenticatorResponse response, String method,
@@ -471,4 +503,54 @@ public abstract class AbstractAccountAuthenticator {
        result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
        return result;
    }

    /**
     * @hide
     * Returns a Bundle that contains whatever is required to clone the account on a different
     * user. The Bundle is passed to the authenticator instance in the target user via
     * {@link #addAccountFromCredentials(AccountAuthenticatorResponse, Account, Bundle)}.
     * The default implementation returns null, indicating that cloning is not supported.
     * @param response to send the result back to the AccountManager, will never be null
     * @param account the account to clone, will never be null
     * @return a Bundle result or null if the result is to be returned via the response.
     * @throws NetworkErrorException
     * @see {@link #addAccountFromCredentials(AccountAuthenticatorResponse, Account, Bundle)}
     */
    public Bundle getAccountCredentialsForCloning(final AccountAuthenticatorResponse response,
            final Account account) throws NetworkErrorException {
        new Thread(new Runnable() {
            public void run() {
                Bundle result = new Bundle();
                result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
                response.onResult(result);
            }
        }).start();
        return null;
    }

    /**
     * @hide
     * Creates an account based on credentials provided by the authenticator instance of another
     * user on the device, who has chosen to share the account with this user.
     * @param response to send the result back to the AccountManager, will never be null
     * @param account the account to clone, will never be null
     * @param accountCredentials the Bundle containing the required credentials to create the
     * account. Contents of the Bundle are only meaningful to the authenticator. This Bundle is
     * provided by {@link #getAccountCredentialsForCloning(AccountAuthenticatorResponse, Account)}.
     * @return a Bundle result or null if the result is to be returned via the response.
     * @throws NetworkErrorException
     * @see {@link #getAccountCredentialsForCloning(AccountAuthenticatorResponse, Account)}
     */
    public Bundle addAccountFromCredentials(final AccountAuthenticatorResponse response,
            Account account,
            Bundle accountCredentials) throws NetworkErrorException {
        new Thread(new Runnable() {
            public void run() {
                Bundle result = new Bundle();
                result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
                response.onResult(result);
            }
        }).start();
        return null;
    }
}
+51 −0
Original line number Diff line number Diff line
@@ -1122,6 +1122,57 @@ public class AccountManager {
        }.start();
    }

    /**
     * Adds a shared account from the primary user to a secondary user. Adding the shared account
     * doesn't take effect immediately. When the target user starts up, any pending shared accounts
     * are attempted to be copied to the target user from the primary via calls to the
     * authenticator.
     * @param account the account to share
     * @param user the target user
     * @return
     * @hide
     */
    public boolean addSharedAccount(final Account account, UserHandle user) {
        try {
            boolean val = mService.addSharedAccountAsUser(account, user.getIdentifier());
            return val;
        } catch (RemoteException re) {
            // won't ever happen
            throw new RuntimeException(re);
        }
    }

    /**
     * @hide
     * Removes the shared account.
     * @param account the account to remove
     * @param user the user to remove the account from
     * @return
     */
    public boolean removeSharedAccount(final Account account, UserHandle user) {
        try {
            boolean val = mService.removeSharedAccountAsUser(account, user.getIdentifier());
            return val;
        } catch (RemoteException re) {
            // won't ever happen
            throw new RuntimeException(re);
        }
    }

    /**
     * @hide
     * @param user
     * @return
     */
    public Account[] getSharedAccounts(UserHandle user) {
        try {
            return mService.getSharedAccountsAsUser(user.getIdentifier());
        } catch (RemoteException re) {
            // won't ever happen
            throw new RuntimeException(re);
        }
    }

    /**
     * Confirms that the user knows the password for an account to make extra
     * sure they are the owner of the account.  The user-entered password can
+13 −0
Original line number Diff line number Diff line
@@ -70,4 +70,17 @@ oneway interface IAccountAuthenticator {
     * Gets whether or not the account is allowed to be removed.
     */
    void getAccountRemovalAllowed(in IAccountAuthenticatorResponse response, in Account account);

    /**
     * Returns a Bundle containing the required credentials to copy the account across users.
     */
    void getAccountCredentialsForCloning(in IAccountAuthenticatorResponse response,
            in Account account);

    /**
     * Uses the Bundle containing credentials from another instance of the authenticator to create
     * a copy of the account on this user.
     */
    void addAccountFromCredentials(in IAccountAuthenticatorResponse response, in Account account,
            in Bundle accountCredentials);
}
+5 −0
Original line number Diff line number Diff line
@@ -58,4 +58,9 @@ interface IAccountManager {
        in Bundle options, boolean expectActivityLaunch, int userId);
    void getAuthTokenLabel(in IAccountManagerResponse response, String accountType,
        String authTokenType);

    /* Shared accounts */
    boolean addSharedAccountAsUser(in Account account, int userId);
    Account[] getSharedAccountsAsUser(int userId);
    boolean removeSharedAccountAsUser(in Account account, int userId);
}
Loading