下面列出了android.content.SyncInfo#android.content.SyncAdapterType 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private void whiteListExistingSyncAdaptersIfNeeded() {
if (!mSyncStorageEngine.shouldGrantSyncAdaptersAccountAccess()) {
return;
}
List<UserInfo> users = mUserManager.getUsers(true);
final int userCount = users.size();
for (int i = 0; i < userCount; i++) {
UserHandle userHandle = users.get(i).getUserHandle();
final int userId = userHandle.getIdentifier();
for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> service
: mSyncAdapters.getAllServices(userId)) {
String packageName = service.componentName.getPackageName();
for (Account account : mAccountManager.getAccountsByTypeAsUser(
service.type.accountType, userHandle)) {
if (!canAccessAccount(account, packageName, userId)) {
mAccountManager.updateAppPermission(account,
AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, service.uid, true);
}
}
}
}
}
static void sendOnUnsyncableAccount(@NonNull Context context,
@NonNull RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo,
@UserIdInt int userId, @NonNull OnReadyCallback onReadyCallback) {
OnUnsyncableAccountCheck connection = new OnUnsyncableAccountCheck(syncAdapterInfo,
onReadyCallback);
boolean isBound = context.bindServiceAsUser(
getAdapterBindIntent(context, syncAdapterInfo.componentName, userId),
connection, SYNC_ADAPTER_CONNECTION_FLAGS, UserHandle.of(userId));
if (isBound) {
// Unbind after SERVICE_BOUND_TIME_MILLIS to not leak the connection.
(new Handler(Looper.getMainLooper())).postDelayed(
() -> context.unbindService(connection),
OnUnsyncableAccountCheck.SERVICE_BOUND_TIME_MILLIS);
} else {
/*
* The default implementation of adapter.onUnsyncableAccount returns true. Hence if
* there the service cannot be bound, assume the default behavior.
*/
connection.onReady();
}
}
/**
* Get information about the SyncAdapters that are known to the system for a particular user.
*
* <p> If the user id supplied is different to the calling user, the caller must hold the
* INTERACT_ACROSS_USERS_FULL permission.
*
* @return an array of SyncAdapters that have registered with the system
*/
@Override
public SyncAdapterType[] getSyncAdapterTypesAsUser(int userId) {
enforceCrossUserPermission(userId,
"no permission to read sync settings for user " + userId);
// This makes it so that future permission checks will be in the context of this
// process rather than the caller's process. We will restore this before returning.
final long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
return syncManager.getSyncAdapterTypes(userId);
} finally {
restoreCallingIdentity(identityToken);
}
}
/**
* Get information about the SyncAdapters that are known to the system for a particular user.
*
* <p> If the user id supplied is different to the calling user, the caller must hold the
* INTERACT_ACROSS_USERS_FULL permission.
*
* @return an array of SyncAdapters that have registered with the system
*/
@Override
public SyncAdapterType[] getSyncAdapterTypesAsUser(int userId) {
enforceCrossUserPermission(userId,
"no permission to read sync settings for user " + userId);
// This makes it so that future permission checks will be in the context of this
// process rather than the caller's process. We will restore this before returning.
final long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
return syncManager.getSyncAdapterTypes(userId);
} finally {
restoreCallingIdentity(identityToken);
}
}
private int getIsSyncable(Account account, int userId, String providerName) {
int isSyncable = mSyncStorageEngine.getIsSyncable(account, userId, providerName);
UserInfo userInfo = UserManager.get(mContext).getUserInfo(userId);
// If it's not a restricted user, return isSyncable.
if (userInfo == null || !userInfo.isRestricted()) return isSyncable;
// Else check if the sync adapter has opted-in or not.
RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
mSyncAdapters.getServiceInfo(
SyncAdapterType.newKey(providerName, account.type), userId);
if (syncAdapterInfo == null) return AuthorityInfo.NOT_SYNCABLE;
PackageInfo pInfo = null;
try {
pInfo = AppGlobals.getPackageManager().getPackageInfo(
syncAdapterInfo.componentName.getPackageName(), 0, userId);
if (pInfo == null) return AuthorityInfo.NOT_SYNCABLE;
} catch (RemoteException re) {
// Shouldn't happen.
return AuthorityInfo.NOT_SYNCABLE;
}
if (pInfo.restrictedAccountType != null
&& pInfo.restrictedAccountType.equals(account.type)) {
return isSyncable;
} else {
return AuthorityInfo.NOT_SYNCABLE;
}
}
public int computeSyncable(Account account, int userId, String authority,
boolean checkAccountAccess) {
final int status = getIsSyncable(account, userId, authority);
if (status == AuthorityInfo.NOT_SYNCABLE) {
return AuthorityInfo.NOT_SYNCABLE;
}
final SyncAdapterType type = SyncAdapterType.newKey(authority, account.type);
final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
mSyncAdapters.getServiceInfo(type, userId);
if (syncAdapterInfo == null) {
return AuthorityInfo.NOT_SYNCABLE;
}
final int owningUid = syncAdapterInfo.uid;
final String owningPackage = syncAdapterInfo.componentName.getPackageName();
try {
if (ActivityManager.getService().isAppStartModeDisabled(owningUid, owningPackage)) {
Slog.w(TAG, "Not scheduling job " + syncAdapterInfo.uid + ":"
+ syncAdapterInfo.componentName
+ " -- package not allowed to start");
return AuthorityInfo.NOT_SYNCABLE;
}
} catch (RemoteException e) {
/* ignore - local call */
}
if (checkAccountAccess && !canAccessAccount(account, owningPackage, owningUid)) {
Log.w(TAG, "Access to " + logSafe(account) + " denied for package "
+ owningPackage + " in UID " + syncAdapterInfo.uid);
return AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS;
}
return status;
}
public SyncAdapterType[] getSyncAdapterTypes(int userId) {
final Collection<RegisteredServicesCache.ServiceInfo<SyncAdapterType>> serviceInfos;
serviceInfos = mSyncAdapters.getAllServices(userId);
SyncAdapterType[] types = new SyncAdapterType[serviceInfos.size()];
int i = 0;
for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> serviceInfo : serviceInfos) {
types[i] = serviceInfo.type;
++i;
}
return types;
}
/**
* Get information about the SyncAdapters that are known to the system for a particular user.
*
* <p> If the user id supplied is different to the calling user, the caller must hold the
* INTERACT_ACROSS_USERS_FULL permission.
*
* @return an array of SyncAdapters that have registered with the system
*/
@Override
public SyncAdapterType[] getSyncAdapterTypesAsUser(int userId) {
enforceCrossUserPermission(userId,
"no permission to read sync settings for user " + userId);
// This makes it so that future permission checks will be in the context of this
// process rather than the caller's process. We will restore this before returning.
final long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
return syncManager.getSyncAdapterTypes(userId);
} finally {
restoreCallingIdentity(identityToken);
}
}
/**
* Enables syncing of a SyncAdapter for a given content provider.
*
* <p>Adds the authority to a whitelist, and immediately requests a sync.
*
* @param username Username of the account (including @gmail.com).
* @param authority The authority of a content provider that should be synced.
*/
@Rpc(description = "Enables syncing of a SyncAdapter for a content provider.")
public void startSync(String username, String authority) throws AccountSnippetException {
if (!listAccounts().contains(username)) {
throw new AccountSnippetException("Account " + username + " is not on the device");
}
// Add to the whitelist
mLock.writeLock().lock();
try {
if (mSyncWhitelist.containsKey(username)) {
mSyncWhitelist.get(username).add(authority);
} else {
mSyncWhitelist.put(username, new HashSet<String>(Arrays.asList(authority)));
}
// Update the Sync settings
for (SyncAdapterType adapter : ContentResolver.getSyncAdapterTypes()) {
// Find the Google account content provider.
if (adapter.accountType.equals(GOOGLE_ACCOUNT_TYPE)
&& adapter.authority.equals(authority)) {
Account account = new Account(username, GOOGLE_ACCOUNT_TYPE);
updateSync(account, authority, true);
}
}
} finally {
mLock.writeLock().unlock();
}
}
/**
* Disables syncing of a SyncAdapter for a given content provider.
*
* <p>Removes the content provider authority from a whitelist.
*
* @param username Username of the account (including @gmail.com).
* @param authority The authority of a content provider that should not be synced.
*/
@Rpc(description = "Disables syncing of a SyncAdapter for a content provider.")
public void stopSync(String username, String authority) throws AccountSnippetException {
if (!listAccounts().contains(username)) {
throw new AccountSnippetException("Account " + username + " is not on the device");
}
// Remove from whitelist
mLock.writeLock().lock();
try {
if (mSyncWhitelist.containsKey(username)) {
Set<String> whitelistedProviders = mSyncWhitelist.get(username);
whitelistedProviders.remove(authority);
if (whitelistedProviders.isEmpty()) {
mSyncWhitelist.remove(username);
}
}
// Update the Sync settings
for (SyncAdapterType adapter : ContentResolver.getSyncAdapterTypes()) {
// Find the Google account content provider.
if (adapter.accountType.equals(GOOGLE_ACCOUNT_TYPE)
&& adapter.authority.equals(authority)) {
Account account = new Account(username, GOOGLE_ACCOUNT_TYPE);
updateSync(account, authority, false);
}
}
} finally {
mLock.writeLock().unlock();
}
}
/**
* Get information about the SyncAdapters that are known to the system.
* @return an array of SyncAdapters that have registered with the system
*/
@Override
public SyncAdapterType[] getSyncAdapterTypes() {
return getSyncAdapterTypesAsUser(UserHandle.getCallingUserId());
}
/**
* Get information about the SyncAdapters that are known to the system.
* @return an array of SyncAdapters that have registered with the system
*/
@Override
public SyncAdapterType[] getSyncAdapterTypes() {
return getSyncAdapterTypesAsUser(UserHandle.getCallingUserId());
}
OnUnsyncableAccountCheck(
@NonNull RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo,
@NonNull OnReadyCallback onReadyCallback) {
mSyncAdapterInfo = syncAdapterInfo;
mOnReadyCallback = onReadyCallback;
}
private boolean dispatchSyncOperation(SyncOperation op) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Slog.v(TAG, "dispatchSyncOperation: we are going to sync " + op);
Slog.v(TAG, "num active syncs: " + mActiveSyncContexts.size());
for (ActiveSyncContext syncContext : mActiveSyncContexts) {
Slog.v(TAG, syncContext.toString());
}
}
if (op.isAppStandbyExempted()) {
final UsageStatsManagerInternal usmi = LocalServices.getService(
UsageStatsManagerInternal.class);
if (usmi != null) {
usmi.reportExemptedSyncStart(op.owningPackage,
UserHandle.getUserId(op.owningUid));
}
}
// Connect to the sync adapter.
int targetUid;
ComponentName targetComponent;
final SyncStorageEngine.EndPoint info = op.target;
SyncAdapterType syncAdapterType =
SyncAdapterType.newKey(info.provider, info.account.type);
final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
syncAdapterInfo = mSyncAdapters.getServiceInfo(syncAdapterType, info.userId);
if (syncAdapterInfo == null) {
mLogger.log("dispatchSyncOperation() failed: no sync adapter info for ",
syncAdapterType);
Log.d(TAG, "can't find a sync adapter for " + syncAdapterType
+ ", removing settings for it");
mSyncStorageEngine.removeAuthority(info);
return false;
}
targetUid = syncAdapterInfo.uid;
targetComponent = syncAdapterInfo.componentName;
ActiveSyncContext activeSyncContext =
new ActiveSyncContext(op, insertStartSyncEvent(op), targetUid);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Slog.v(TAG, "dispatchSyncOperation: starting " + activeSyncContext);
}
activeSyncContext.mSyncInfo = mSyncStorageEngine.addActiveSync(activeSyncContext);
mActiveSyncContexts.add(activeSyncContext);
// Post message to begin monitoring this sync's progress.
postMonitorSyncProgressMessage(activeSyncContext);
if (!activeSyncContext.bindToSyncAdapter(targetComponent, info.userId)) {
mLogger.log("dispatchSyncOperation() failed: bind failed. target: ",
targetComponent);
Slog.e(TAG, "Bind attempt failed - target: " + targetComponent);
closeActiveSyncContext(activeSyncContext);
return false;
}
return true;
}
/**
* Get information about the SyncAdapters that are known to the system.
* @return an array of SyncAdapters that have registered with the system
*/
@Override
public SyncAdapterType[] getSyncAdapterTypes() {
return getSyncAdapterTypesAsUser(UserHandle.getCallingUserId());
}
/**
* Adds a Google account to the device.
*
* @param username Username of the account to add (including @gmail.com).
* @param password Password of the account to add.
*/
@Rpc(
description =
"Add a Google (GMail) account to the device, with account data sync disabled.")
public void addAccount(String username, String password)
throws AccountSnippetException, AccountsException, IOException {
// Check for existing account. If we try to re-add an existing account, Android throws an
// exception that says "Account does not exist or not visible. Maybe change pwd?" which is
// a little hard to understand.
if (listAccounts().contains(username)) {
throw new AccountSnippetException(
"Account " + username + " already exists on the device");
}
Bundle addAccountOptions = new Bundle();
addAccountOptions.putString("username", username);
addAccountOptions.putString("password", password);
AccountManagerFuture<Bundle> future =
mAccountManager.addAccount(
GOOGLE_ACCOUNT_TYPE,
AUTH_TOKEN_TYPE,
null /* requiredFeatures */,
addAccountOptions,
null /* activity */,
null /* authCallback */,
null /* handler */);
Bundle result = future.getResult();
if (result.containsKey(AccountManager.KEY_ERROR_CODE)) {
throw new AccountSnippetException(
String.format(
Locale.US,
"Failed to add account due to code %d: %s",
result.getInt(AccountManager.KEY_ERROR_CODE),
result.getString(AccountManager.KEY_ERROR_MESSAGE)));
}
// Disable sync to avoid test flakiness as accounts fetch additional data.
// It takes a while for all sync adapters to be populated, so register for broadcasts when
// sync is starting and disable them there.
// NOTE: this listener is NOT unregistered because several sync requests for the new account
// will come in over time.
Account account = new Account(username, GOOGLE_ACCOUNT_TYPE);
Object handle =
ContentResolver.addStatusChangeListener(
ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE
| ContentResolver.SYNC_OBSERVER_TYPE_PENDING,
which -> {
for (SyncAdapterType adapter : ContentResolver.getSyncAdapterTypes()) {
// Ignore non-Google account types.
if (!adapter.accountType.equals(GOOGLE_ACCOUNT_TYPE)) {
continue;
}
// If a content provider is not whitelisted, then disable it.
// Because startSync and stopSync synchronously update the whitelist
// and sync settings, writelock both the whitelist check and the
// call to sync together.
mLock.writeLock().lock();
try {
if (!isAdapterWhitelisted(username, adapter.authority)) {
updateSync(account, adapter.authority, false /* sync */);
}
} finally {
mLock.writeLock().unlock();
}
}
});
mSyncStatusObserverHandles.add(handle);
}
@Override
protected void after(XParam param) throws Throwable {
switch (mMethod) {
case getCurrentSync:
if (isRestricted(param))
param.setResult(null);
break;
case getCurrentSyncs:
if (isRestricted(param))
param.setResult(new ArrayList<SyncInfo>());
break;
case getSyncAdapterTypes:
if (isRestricted(param))
param.setResult(new SyncAdapterType[0]);
break;
case openAssetFileDescriptor:
case openFileDescriptor:
case openInputStream:
case openOutputStream:
case openTypedAssetFileDescriptor:
case openAssetFile:
case openFile:
if (param.args.length > 0 && param.args[0] instanceof Uri) {
String uri = ((Uri) param.args[0]).toString();
if (isRestrictedExtra(param, uri))
param.setThrowable(new FileNotFoundException("XPrivacy"));
}
break;
case Srv_call:
handleCallAfter(param);
break;
case query:
case Srv_query:
handleUriAfter(param);
break;
case Srv_getCurrentSyncs:
case Srv_getCurrentSyncsAsUser:
if (param.getResult() != null)
if (isRestricted(param)) {
int uid = Binder.getCallingUid();
@SuppressWarnings("unchecked")
List<SyncInfo> listSync = (List<SyncInfo>) param.getResult();
List<SyncInfo> listFiltered = new ArrayList<SyncInfo>();
for (SyncInfo sync : listSync)
if (XAccountManager.isAccountAllowed(sync.account, uid))
listFiltered.add(sync);
param.setResult(listFiltered);
}
break;
}
}