[DO NOT MERGE] Backup account access grants
am: 72ed12c55f
Change-Id: I80029a2db1cbddc22ae545879fd757446610e154
This commit is contained in:
@@ -73,4 +73,18 @@ public abstract class AccountManagerInternal {
|
||||
*/
|
||||
public abstract void addOnAppPermissionChangeListener(
|
||||
@NonNull OnAppPermissionChangeListener listener);
|
||||
|
||||
/**
|
||||
* Backups the account access permissions.
|
||||
* @param userId The user for which to backup.
|
||||
* @return The backup data.
|
||||
*/
|
||||
public abstract byte[] backupAccountAccessPermissions(int userId);
|
||||
|
||||
/**
|
||||
* Restores the account access permissions.
|
||||
* @param data The restore data.
|
||||
* @param userId The user for which to restore.
|
||||
*/
|
||||
public abstract void restoreAccountAccessPermissions(byte[] data, int userId);
|
||||
}
|
||||
|
||||
96
core/java/android/util/PackageUtils.java
Normal file
96
core/java/android/util/PackageUtils.java
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.util;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.Signature;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* Helper functions applicable to packages.
|
||||
* @hide
|
||||
*/
|
||||
public final class PackageUtils {
|
||||
private final static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
|
||||
|
||||
private PackageUtils() {
|
||||
/* hide constructor */
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the SHA256 digest of the signing cert for a package.
|
||||
* @param packageManager The package manager.
|
||||
* @param packageName The package for which to generate the digest.
|
||||
* @param userId The user for which to generate the digest.
|
||||
* @return The digest or null if the package does not exist for this user.
|
||||
*/
|
||||
public static @Nullable String computePackageCertSha256Digest(
|
||||
@NonNull PackageManager packageManager,
|
||||
@NonNull String packageName, int userId) {
|
||||
final PackageInfo packageInfo;
|
||||
try {
|
||||
packageInfo = packageManager.getPackageInfoAsUser(packageName,
|
||||
PackageManager.GET_SIGNATURES, userId);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
return computeCertSha256Digest(packageInfo.signatures[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the SHA256 digest of a cert.
|
||||
* @param signature The signature.
|
||||
* @return The digest or null if an error occurs.
|
||||
*/
|
||||
public static @Nullable String computeCertSha256Digest(@NonNull Signature signature) {
|
||||
return computeSha256Digest(signature.toByteArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the SHA256 digest of some data.
|
||||
* @param data The data.
|
||||
* @return The digest or null if an error occurs.
|
||||
*/
|
||||
public static @Nullable String computeSha256Digest(@NonNull byte[] data) {
|
||||
MessageDigest messageDigest;
|
||||
try {
|
||||
messageDigest = MessageDigest.getInstance("SHA256");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
/* can't happen */
|
||||
return null;
|
||||
}
|
||||
|
||||
messageDigest.update(data);
|
||||
|
||||
final byte[] digest = messageDigest.digest();
|
||||
final int digestLength = digest.length;
|
||||
final int charCount = 2 * digestLength;
|
||||
|
||||
final char[] chars = new char[charCount];
|
||||
for (int i = 0; i < digestLength; i++) {
|
||||
final int byteHex = digest[i] & 0xFF;
|
||||
chars[i * 2] = HEX_ARRAY[byteHex >>> 4];
|
||||
chars[i * 2 + 1] = HEX_ARRAY[byteHex & 0x0F];
|
||||
}
|
||||
return new String(chars);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.backup;
|
||||
|
||||
import android.accounts.AccountManagerInternal;
|
||||
import android.app.backup.BlobBackupHelper;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Slog;
|
||||
import com.android.server.LocalServices;
|
||||
|
||||
/**
|
||||
* Helper for handling backup of account manager specific state.
|
||||
*/
|
||||
public class AccountManagerBackupHelper extends BlobBackupHelper {
|
||||
private static final String TAG = "AccountsBackup";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
// current schema of the backup state blob
|
||||
private static final int STATE_VERSION = 1;
|
||||
|
||||
// key under which the account access grant state blob is committed to backup
|
||||
private static final String KEY_ACCOUNT_ACCESS_GRANTS = "account_access_grants";
|
||||
|
||||
public AccountManagerBackupHelper() {
|
||||
super(STATE_VERSION, KEY_ACCOUNT_ACCESS_GRANTS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] getBackupPayload(String key) {
|
||||
AccountManagerInternal am = LocalServices.getService(AccountManagerInternal.class);
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Handling backup of " + key);
|
||||
}
|
||||
try {
|
||||
switch (key) {
|
||||
case KEY_ACCOUNT_ACCESS_GRANTS: {
|
||||
return am.backupAccountAccessPermissions(UserHandle.USER_SYSTEM);
|
||||
}
|
||||
|
||||
default: {
|
||||
Slog.w(TAG, "Unexpected backup key " + key);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Slog.e(TAG, "Unable to store payload " + key);
|
||||
}
|
||||
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyRestoredPayload(String key, byte[] payload) {
|
||||
AccountManagerInternal am = LocalServices.getService(AccountManagerInternal.class);
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Handling restore of " + key);
|
||||
}
|
||||
try {
|
||||
switch (key) {
|
||||
case KEY_ACCOUNT_ACCESS_GRANTS: {
|
||||
am.restoreAccountAccessPermissions(payload, UserHandle.USER_SYSTEM);
|
||||
} break;
|
||||
|
||||
default: {
|
||||
Slog.w(TAG, "Unexpected restore key " + key);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Slog.w(TAG, "Unable to restore key " + key);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,6 +49,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
|
||||
private static final String PERMISSION_HELPER = "permissions";
|
||||
private static final String USAGE_STATS_HELPER = "usage_stats";
|
||||
private static final String SHORTCUT_MANAGER_HELPER = "shortcut_manager";
|
||||
private static final String ACCOUNT_MANAGER_HELPER = "account_manager";
|
||||
|
||||
// These paths must match what the WallpaperManagerService uses. The leaf *_FILENAME
|
||||
// are also used in the full-backup file format, so must not change unless steps are
|
||||
@@ -82,6 +83,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
|
||||
addHelper(PERMISSION_HELPER, new PermissionBackupHelper());
|
||||
addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
|
||||
addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
|
||||
addHelper(ACCOUNT_MANAGER_HELPER, new AccountManagerBackupHelper());
|
||||
super.onBackup(oldState, data, newState);
|
||||
}
|
||||
|
||||
@@ -111,6 +113,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
|
||||
addHelper(PERMISSION_HELPER, new PermissionBackupHelper());
|
||||
addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
|
||||
addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
|
||||
addHelper(ACCOUNT_MANAGER_HELPER, new AccountManagerBackupHelper());
|
||||
|
||||
try {
|
||||
super.onRestore(data, appVersionCode, newState);
|
||||
|
||||
@@ -0,0 +1,312 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.accounts;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.accounts.AccountManagerInternal;
|
||||
import android.annotation.IntRange;
|
||||
import android.annotation.NonNull;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.os.UserHandle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.PackageUtils;
|
||||
import android.util.Xml;
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.content.PackageMonitor;
|
||||
import com.android.internal.util.FastXmlSerializer;
|
||||
import com.android.internal.util.XmlUtils;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Helper class for backup and restore of account access grants.
|
||||
*/
|
||||
public final class AccountManagerBackupHelper {
|
||||
private static final String TAG = "AccountManagerBackupHelper";
|
||||
|
||||
private static final long PENDING_RESTORE_TIMEOUT_MILLIS = 60 * 60 * 1000; // 1 hour
|
||||
|
||||
private static final String TAG_PERMISSIONS = "permissions";
|
||||
private static final String TAG_PERMISSION = "permission";
|
||||
private static final String ATTR_ACCOUNT_SHA_256 = "account-sha-256";
|
||||
private static final String ATTR_PACKAGE = "package";
|
||||
private static final String ATTR_DIGEST = "digest";
|
||||
|
||||
private static final String ACCOUNT_ACCESS_GRANTS = ""
|
||||
+ "SELECT " + AccountManagerService.ACCOUNTS_NAME + ", "
|
||||
+ AccountManagerService.GRANTS_GRANTEE_UID
|
||||
+ " FROM " + AccountManagerService.TABLE_ACCOUNTS
|
||||
+ ", " + AccountManagerService.TABLE_GRANTS
|
||||
+ " WHERE " + AccountManagerService.GRANTS_ACCOUNTS_ID
|
||||
+ "=" + AccountManagerService.ACCOUNTS_ID;
|
||||
|
||||
private final Object mLock = new Object();
|
||||
|
||||
private final AccountManagerService mAccountManagerService;
|
||||
private final AccountManagerInternal mAccountManagerInternal;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private List<PendingAppPermission> mRestorePendingAppPermissions;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private RestorePackageMonitor mRestorePackageMonitor;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private Runnable mRestoreCancelCommand;
|
||||
|
||||
public AccountManagerBackupHelper(AccountManagerService accountManagerService,
|
||||
AccountManagerInternal accountManagerInternal) {
|
||||
mAccountManagerService = accountManagerService;
|
||||
mAccountManagerInternal = accountManagerInternal;
|
||||
}
|
||||
|
||||
private final class PendingAppPermission {
|
||||
private final @NonNull String accountDigest;
|
||||
private final @NonNull String packageName;
|
||||
private final @NonNull String certDigest;
|
||||
private final @IntRange(from = 0) int userId;
|
||||
|
||||
public PendingAppPermission(String accountDigest, String packageName,
|
||||
String certDigest, int userId) {
|
||||
this.accountDigest = accountDigest;
|
||||
this.packageName = packageName;
|
||||
this.certDigest = certDigest;
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public boolean apply(PackageManager packageManager) {
|
||||
Account account = null;
|
||||
AccountManagerService.UserAccounts accounts = mAccountManagerService
|
||||
.getUserAccounts(userId);
|
||||
synchronized (accounts.cacheLock) {
|
||||
for (Account[] accountsPerType : accounts.accountCache.values()) {
|
||||
for (Account accountPerType : accountsPerType) {
|
||||
if (accountDigest.equals(PackageUtils.computeSha256Digest(
|
||||
accountPerType.name.getBytes()))) {
|
||||
account = accountPerType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (account != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (account == null) {
|
||||
return false;
|
||||
}
|
||||
final PackageInfo packageInfo;
|
||||
try {
|
||||
packageInfo = packageManager.getPackageInfoAsUser(packageName,
|
||||
PackageManager.GET_SIGNATURES, userId);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
String currentCertDigest = PackageUtils.computeCertSha256Digest(
|
||||
packageInfo.signatures[0]);
|
||||
if (!certDigest.equals(currentCertDigest)) {
|
||||
return false;
|
||||
}
|
||||
final int uid = packageInfo.applicationInfo.uid;
|
||||
if (!mAccountManagerInternal.hasAccountAccess(account, uid)) {
|
||||
mAccountManagerService.grantAppPermission(account,
|
||||
AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] backupAccountAccessPermissions(int userId) {
|
||||
final AccountManagerService.UserAccounts accounts = mAccountManagerService
|
||||
.getUserAccounts(userId);
|
||||
synchronized (accounts.cacheLock) {
|
||||
SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
|
||||
try (
|
||||
Cursor cursor = db.rawQuery(ACCOUNT_ACCESS_GRANTS, null);
|
||||
) {
|
||||
if (cursor == null || !cursor.moveToFirst()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final int nameColumnIdx = cursor.getColumnIndex(
|
||||
AccountManagerService.ACCOUNTS_NAME);
|
||||
final int uidColumnIdx = cursor.getColumnIndex(
|
||||
AccountManagerService.GRANTS_GRANTEE_UID);
|
||||
|
||||
ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
|
||||
try {
|
||||
final XmlSerializer serializer = new FastXmlSerializer();
|
||||
serializer.setOutput(dataStream, StandardCharsets.UTF_8.name());
|
||||
serializer.startDocument(null, true);
|
||||
serializer.startTag(null, TAG_PERMISSIONS);
|
||||
|
||||
PackageManager packageManager = mAccountManagerService.mContext
|
||||
.getPackageManager();
|
||||
|
||||
do {
|
||||
final String accountName = cursor.getString(nameColumnIdx);
|
||||
final int uid = cursor.getInt(uidColumnIdx);
|
||||
|
||||
final String[] packageNames = packageManager.getPackagesForUid(uid);
|
||||
if (packageNames == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (String packageName : packageNames) {
|
||||
String digest = PackageUtils.computePackageCertSha256Digest(
|
||||
packageManager, packageName, userId);
|
||||
if (digest != null) {
|
||||
serializer.startTag(null, TAG_PERMISSION);
|
||||
serializer.attribute(null, ATTR_ACCOUNT_SHA_256,
|
||||
PackageUtils.computeSha256Digest(accountName.getBytes()));
|
||||
serializer.attribute(null, ATTR_PACKAGE, packageName);
|
||||
serializer.attribute(null, ATTR_DIGEST, digest);
|
||||
serializer.endTag(null, TAG_PERMISSION);
|
||||
}
|
||||
}
|
||||
} while (cursor.moveToNext());
|
||||
|
||||
serializer.endTag(null, TAG_PERMISSIONS);
|
||||
serializer.endDocument();
|
||||
serializer.flush();
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Error backing up account access grants", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
return dataStream.toByteArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void restoreAccountAccessPermissions(byte[] data, int userId) {
|
||||
try {
|
||||
ByteArrayInputStream dataStream = new ByteArrayInputStream(data);
|
||||
XmlPullParser parser = Xml.newPullParser();
|
||||
parser.setInput(dataStream, StandardCharsets.UTF_8.name());
|
||||
PackageManager packageManager = mAccountManagerService.mContext.getPackageManager();
|
||||
|
||||
final int permissionsOuterDepth = parser.getDepth();
|
||||
while (XmlUtils.nextElementWithin(parser, permissionsOuterDepth)) {
|
||||
if (!TAG_PERMISSIONS.equals(parser.getName())) {
|
||||
continue;
|
||||
}
|
||||
final int permissionOuterDepth = parser.getDepth();
|
||||
while (XmlUtils.nextElementWithin(parser, permissionOuterDepth)) {
|
||||
if (!TAG_PERMISSION.equals(parser.getName())) {
|
||||
continue;
|
||||
}
|
||||
String accountDigest = parser.getAttributeValue(null, ATTR_ACCOUNT_SHA_256);
|
||||
if (TextUtils.isEmpty(accountDigest)) {
|
||||
XmlUtils.skipCurrentTag(parser);
|
||||
}
|
||||
String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
|
||||
if (TextUtils.isEmpty(packageName)) {
|
||||
XmlUtils.skipCurrentTag(parser);
|
||||
}
|
||||
String digest = parser.getAttributeValue(null, ATTR_DIGEST);
|
||||
if (TextUtils.isEmpty(digest)) {
|
||||
XmlUtils.skipCurrentTag(parser);
|
||||
}
|
||||
|
||||
PendingAppPermission pendingAppPermission = new PendingAppPermission(
|
||||
accountDigest, packageName, digest, userId);
|
||||
|
||||
if (!pendingAppPermission.apply(packageManager)) {
|
||||
synchronized (mLock) {
|
||||
// Start watching before add pending to avoid a missed signal
|
||||
if (mRestorePackageMonitor == null) {
|
||||
mRestorePackageMonitor = new RestorePackageMonitor();
|
||||
mRestorePackageMonitor.register(mAccountManagerService.mContext,
|
||||
mAccountManagerService.mMessageHandler.getLooper(), true);
|
||||
}
|
||||
if (mRestorePendingAppPermissions == null) {
|
||||
mRestorePendingAppPermissions = new ArrayList<>();
|
||||
}
|
||||
mRestorePendingAppPermissions.add(pendingAppPermission);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we eventually prune the in-memory pending restores
|
||||
mRestoreCancelCommand = new CancelRestoreCommand();
|
||||
mAccountManagerService.mMessageHandler.postDelayed(mRestoreCancelCommand,
|
||||
PENDING_RESTORE_TIMEOUT_MILLIS);
|
||||
} catch (XmlPullParserException | IOException e) {
|
||||
Log.e(TAG, "Error restoring app permissions", e);
|
||||
}
|
||||
}
|
||||
|
||||
private final class RestorePackageMonitor extends PackageMonitor {
|
||||
@Override
|
||||
public void onPackageAdded(String packageName, int uid) {
|
||||
synchronized (mLock) {
|
||||
if (mRestorePendingAppPermissions == null) {
|
||||
return;
|
||||
}
|
||||
if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
|
||||
return;
|
||||
}
|
||||
final int count = mRestorePendingAppPermissions.size();
|
||||
for (int i = count - 1; i >= 0; i--) {
|
||||
PendingAppPermission pendingAppPermission =
|
||||
mRestorePendingAppPermissions.get(i);
|
||||
if (!pendingAppPermission.packageName.equals(packageName)) {
|
||||
continue;
|
||||
}
|
||||
if (pendingAppPermission.apply(
|
||||
mAccountManagerService.mContext.getPackageManager())) {
|
||||
mRestorePendingAppPermissions.remove(i);
|
||||
}
|
||||
}
|
||||
if (mRestorePendingAppPermissions.isEmpty()
|
||||
&& mRestoreCancelCommand != null) {
|
||||
mAccountManagerService.mMessageHandler.removeCallbacks(mRestoreCancelCommand);
|
||||
mRestoreCancelCommand.run();
|
||||
mRestoreCancelCommand = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class CancelRestoreCommand implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (mLock) {
|
||||
mRestorePendingAppPermissions = null;
|
||||
if (mRestorePackageMonitor != null) {
|
||||
mRestorePackageMonitor.unregister();
|
||||
mRestorePackageMonitor = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,12 +89,14 @@ import android.os.UserManager;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.PackageUtils;
|
||||
import android.util.Pair;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseBooleanArray;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.content.PackageMonitor;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
@@ -156,13 +158,6 @@ public class AccountManagerService
|
||||
publishBinderService(Context.ACCOUNT_SERVICE, mService);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBootPhase(int phase) {
|
||||
if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
|
||||
mService.systemReady();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnlockUser(int userHandle) {
|
||||
mService.onUnlockUser(userHandle);
|
||||
@@ -176,13 +171,13 @@ public class AccountManagerService
|
||||
|
||||
private static final int MAX_DEBUG_DB_SIZE = 64;
|
||||
|
||||
private final Context mContext;
|
||||
final Context mContext;
|
||||
|
||||
private final PackageManager mPackageManager;
|
||||
private final AppOpsManager mAppOpsManager;
|
||||
private UserManager mUserManager;
|
||||
|
||||
private final MessageHandler mMessageHandler;
|
||||
final MessageHandler mMessageHandler;
|
||||
|
||||
// Messages that can be sent on mHandler
|
||||
private static final int MESSAGE_TIMED_OUT = 3;
|
||||
@@ -190,9 +185,9 @@ public class AccountManagerService
|
||||
|
||||
private final IAccountAuthenticatorCache mAuthenticatorCache;
|
||||
|
||||
private static final String TABLE_ACCOUNTS = "accounts";
|
||||
private static final String ACCOUNTS_ID = "_id";
|
||||
private static final String ACCOUNTS_NAME = "name";
|
||||
static final String TABLE_ACCOUNTS = "accounts";
|
||||
static final String ACCOUNTS_ID = "_id";
|
||||
static final String ACCOUNTS_NAME = "name";
|
||||
private static final String ACCOUNTS_TYPE = "type";
|
||||
private static final String ACCOUNTS_TYPE_COUNT = "count(type)";
|
||||
private static final String ACCOUNTS_PASSWORD = "password";
|
||||
@@ -206,10 +201,10 @@ public class AccountManagerService
|
||||
private static final String AUTHTOKENS_TYPE = "type";
|
||||
private static final String AUTHTOKENS_AUTHTOKEN = "authtoken";
|
||||
|
||||
private static final String TABLE_GRANTS = "grants";
|
||||
private static final String GRANTS_ACCOUNTS_ID = "accounts_id";
|
||||
static final String TABLE_GRANTS = "grants";
|
||||
static final String GRANTS_ACCOUNTS_ID = "accounts_id";
|
||||
private static final String GRANTS_AUTH_TOKEN_TYPE = "auth_token_type";
|
||||
private static final String GRANTS_GRANTEE_UID = "uid";
|
||||
static final String GRANTS_GRANTEE_UID = "uid";
|
||||
|
||||
private static final String TABLE_EXTRAS = "extras";
|
||||
private static final String EXTRAS_ID = "_id";
|
||||
@@ -276,15 +271,15 @@ public class AccountManagerService
|
||||
|
||||
static class UserAccounts {
|
||||
private final int userId;
|
||||
private final DeDatabaseHelper openHelper;
|
||||
final DeDatabaseHelper openHelper;
|
||||
private final HashMap<Pair<Pair<Account, String>, Integer>, Integer>
|
||||
credentialsPermissionNotificationIds =
|
||||
new HashMap<Pair<Pair<Account, String>, Integer>, Integer>();
|
||||
private final HashMap<Account, Integer> signinRequiredNotificationIds =
|
||||
new HashMap<Account, Integer>();
|
||||
private final Object cacheLock = new Object();
|
||||
final Object cacheLock = new Object();
|
||||
/** protected by the {@link #cacheLock} */
|
||||
private final HashMap<String, Account[]> accountCache =
|
||||
final HashMap<String, Account[]> accountCache =
|
||||
new LinkedHashMap<>();
|
||||
/** protected by the {@link #cacheLock} */
|
||||
private final HashMap<Account, HashMap<String, String>> userDataCache =
|
||||
@@ -526,9 +521,6 @@ public class AccountManagerService
|
||||
}
|
||||
}
|
||||
|
||||
public void systemReady() {
|
||||
}
|
||||
|
||||
private UserManager getUserManager() {
|
||||
if (mUserManager == null) {
|
||||
mUserManager = UserManager.get(mContext);
|
||||
@@ -4453,7 +4445,7 @@ public class AccountManagerService
|
||||
}
|
||||
}
|
||||
|
||||
private class MessageHandler extends Handler {
|
||||
class MessageHandler extends Handler {
|
||||
MessageHandler(Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
@@ -5604,7 +5596,7 @@ public class AccountManagerService
|
||||
* which is in the system. This means we don't need to protect it with permissions.
|
||||
* @hide
|
||||
*/
|
||||
private void grantAppPermission(Account account, String authTokenType, int uid) {
|
||||
void grantAppPermission(Account account, String authTokenType, int uid) {
|
||||
if (account == null || authTokenType == null) {
|
||||
Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
|
||||
return;
|
||||
@@ -5989,6 +5981,11 @@ public class AccountManagerService
|
||||
}
|
||||
|
||||
private final class AccountManagerInternalImpl extends AccountManagerInternal {
|
||||
private final Object mLock = new Object();
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private AccountManagerBackupHelper mBackupHelper;
|
||||
|
||||
@Override
|
||||
public void requestAccountAccess(@NonNull Account account, @NonNull String packageName,
|
||||
@IntRange(from = 0) int userId, @NonNull RemoteCallback callback) {
|
||||
@@ -6043,5 +6040,27 @@ public class AccountManagerService
|
||||
public boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid) {
|
||||
return AccountManagerService.this.hasAccountAccess(account, null, uid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] backupAccountAccessPermissions(int userId) {
|
||||
synchronized (mLock) {
|
||||
if (mBackupHelper == null) {
|
||||
mBackupHelper = new AccountManagerBackupHelper(
|
||||
AccountManagerService.this, this);
|
||||
}
|
||||
return mBackupHelper.backupAccountAccessPermissions(userId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreAccountAccessPermissions(byte[] data, int userId) {
|
||||
synchronized (mLock) {
|
||||
if (mBackupHelper == null) {
|
||||
mBackupHelper = new AccountManagerBackupHelper(
|
||||
AccountManagerService.this, this);
|
||||
}
|
||||
mBackupHelper.restoreAccountAccessPermissions(data, userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user