1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.content; 18 19 import static android.content.PermissionChecker.PERMISSION_GRANTED; 20 21 import android.Manifest; 22 import android.accounts.Account; 23 import android.accounts.AccountManagerInternal; 24 import android.annotation.NonNull; 25 import android.annotation.Nullable; 26 import android.annotation.RequiresPermission; 27 import android.annotation.UserIdInt; 28 import android.app.ActivityManager; 29 import android.app.ActivityManager.RestrictionLevel; 30 import android.app.ActivityManagerInternal; 31 import android.app.AppGlobals; 32 import android.app.AppOpsManager; 33 import android.app.compat.CompatChanges; 34 import android.app.job.JobInfo; 35 import android.compat.annotation.ChangeId; 36 import android.compat.annotation.EnabledAfter; 37 import android.content.BroadcastReceiver; 38 import android.content.ComponentName; 39 import android.content.ContentResolver; 40 import android.content.ContentResolver.SyncExemption; 41 import android.content.Context; 42 import android.content.IContentService; 43 import android.content.ISyncStatusObserver; 44 import android.content.Intent; 45 import android.content.IntentFilter; 46 import android.content.PeriodicSync; 47 import android.content.SyncAdapterType; 48 import android.content.SyncInfo; 49 import android.content.SyncRequest; 50 import android.content.SyncStatusInfo; 51 import android.content.pm.PackageManager; 52 import android.content.pm.ProviderInfo; 53 import android.database.IContentObserver; 54 import android.net.Uri; 55 import android.os.AppBackgroundRestrictionsInfo; 56 import android.os.Binder; 57 import android.os.Build; 58 import android.os.Bundle; 59 import android.os.FactoryTest; 60 import android.os.IBinder; 61 import android.os.Process; 62 import android.os.RemoteException; 63 import android.os.ResultReceiver; 64 import android.os.ShellCallback; 65 import android.os.UserHandle; 66 import android.text.TextUtils; 67 import android.text.format.DateUtils; 68 import android.util.ArrayMap; 69 import android.util.ArraySet; 70 import android.util.Log; 71 import android.util.Pair; 72 import android.util.Slog; 73 import android.util.SparseArray; 74 import android.util.SparseIntArray; 75 76 import com.android.internal.annotations.GuardedBy; 77 import com.android.internal.annotations.VisibleForTesting; 78 import com.android.internal.os.BackgroundThread; 79 import com.android.internal.os.BinderDeathDispatcher; 80 import com.android.internal.util.ArrayUtils; 81 import com.android.internal.util.DumpUtils; 82 import com.android.internal.util.FrameworkStatsLog; 83 import com.android.internal.util.IndentingPrintWriter; 84 import com.android.server.LocalServices; 85 import com.android.server.SystemService; 86 import com.android.server.pm.permission.LegacyPermissionManagerInternal; 87 88 import java.io.FileDescriptor; 89 import java.io.PrintWriter; 90 import java.util.ArrayList; 91 import java.util.Arrays; 92 import java.util.Collections; 93 import java.util.Comparator; 94 import java.util.List; 95 import java.util.Objects; 96 97 /** 98 * {@hide} 99 */ 100 public final class ContentService extends IContentService.Stub { 101 static final String TAG = "ContentService"; 102 static final boolean DEBUG = false; 103 104 /** Do a WTF if a single observer is registered more than this times. */ 105 private static final int TOO_MANY_OBSERVERS_THRESHOLD = 1000; 106 107 /** 108 * Delay to apply to content change notifications dispatched to apps running 109 * in the background. This is used to help prevent stampeding when the user 110 * is performing CPU/RAM intensive foreground tasks, such as when capturing 111 * burst photos. 112 */ 113 private static final long BACKGROUND_OBSERVER_DELAY = 10 * DateUtils.SECOND_IN_MILLIS; 114 115 /** 116 * Enables checking for account access for the calling uid on all sync-related APIs. 117 */ 118 @ChangeId 119 @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.S_V2) 120 public static final long ACCOUNT_ACCESS_CHECK_CHANGE_ID = 201794303L; 121 122 /** 123 * Enables checking for authority access for the calling uid on all sync-related APIs. 124 */ 125 @ChangeId 126 @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.TIRAMISU) 127 public static final long AUTHORITY_ACCESS_CHECK_CHANGE_ID = 207133734L; 128 129 public static class Lifecycle extends SystemService { 130 private ContentService mService; 131 Lifecycle(Context context)132 public Lifecycle(Context context) { 133 super(context); 134 } 135 136 @Override onStart()137 public void onStart() { 138 final boolean factoryTest = (FactoryTest 139 .getMode() == FactoryTest.FACTORY_TEST_LOW_LEVEL); 140 mService = new ContentService(getContext(), factoryTest); 141 publishBinderService(ContentResolver.CONTENT_SERVICE_NAME, mService); 142 } 143 144 @Override onBootPhase(int phase)145 public void onBootPhase(int phase) { 146 mService.onBootPhase(phase); 147 } 148 149 @Override onUserStarting(@onNull TargetUser user)150 public void onUserStarting(@NonNull TargetUser user) { 151 mService.onStartUser(user.getUserIdentifier()); 152 } 153 154 @Override onUserUnlocking(@onNull TargetUser user)155 public void onUserUnlocking(@NonNull TargetUser user) { 156 mService.onUnlockUser(user.getUserIdentifier()); 157 } 158 159 @Override onUserStopping(@onNull TargetUser user)160 public void onUserStopping(@NonNull TargetUser user) { 161 mService.onStopUser(user.getUserIdentifier()); 162 } 163 164 @Override onUserStopped(@onNull TargetUser user)165 public void onUserStopped(@NonNull TargetUser user) { 166 synchronized (mService.mCache) { 167 mService.mCache.remove(user.getUserIdentifier()); 168 } 169 } 170 } 171 172 private Context mContext; 173 private boolean mFactoryTest; 174 175 private final ObserverNode mRootNode = new ObserverNode(""); 176 177 private SyncManager mSyncManager = null; 178 private final Object mSyncManagerLock = new Object(); 179 180 private final AccountManagerInternal mAccountManagerInternal; 181 182 private static final BinderDeathDispatcher<IContentObserver> sObserverDeathDispatcher = 183 new BinderDeathDispatcher<>(); 184 185 @GuardedBy("sObserverLeakDetectedUid") 186 private static final ArraySet<Integer> sObserverLeakDetectedUid = new ArraySet<>(0); 187 188 /** 189 * Map from userId to providerPackageName to [clientPackageName, uri] to 190 * value. This structure is carefully optimized to keep invalidation logic 191 * as cheap as possible. 192 */ 193 @GuardedBy("mCache") 194 private final SparseArray<ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>>> 195 mCache = new SparseArray<>(); 196 197 private BroadcastReceiver mCacheReceiver = new BroadcastReceiver() { 198 @Override 199 public void onReceive(Context context, Intent intent) { 200 synchronized (mCache) { 201 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) { 202 mCache.clear(); 203 } else { 204 final Uri data = intent.getData(); 205 if (data != null) { 206 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 207 UserHandle.USER_NULL); 208 final String packageName = data.getSchemeSpecificPart(); 209 invalidateCacheLocked(userId, packageName, null); 210 } 211 } 212 } 213 } 214 }; 215 getSyncManager()216 private SyncManager getSyncManager() { 217 synchronized(mSyncManagerLock) { 218 if (mSyncManager == null) { 219 mSyncManager = new SyncManager(mContext, mFactoryTest); 220 } 221 return mSyncManager; 222 } 223 } 224 onStartUser(int userHandle)225 void onStartUser(int userHandle) { 226 if (mSyncManager != null) mSyncManager.onStartUser(userHandle); 227 } 228 onUnlockUser(int userHandle)229 void onUnlockUser(int userHandle) { 230 if (mSyncManager != null) mSyncManager.onUnlockUser(userHandle); 231 } 232 onStopUser(int userHandle)233 void onStopUser(int userHandle) { 234 if (mSyncManager != null) mSyncManager.onStopUser(userHandle); 235 } 236 237 @Override dump(FileDescriptor fd, PrintWriter pw_, String[] args)238 protected synchronized void dump(FileDescriptor fd, PrintWriter pw_, String[] args) { 239 if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw_)) return; 240 final IndentingPrintWriter pw = new IndentingPrintWriter(pw_, " "); 241 242 final boolean dumpAll = ArrayUtils.contains(args, "-a"); 243 244 // This makes it so that future permission checks will be in the context of this 245 // process rather than the caller's process. We will restore this before returning. 246 final long identityToken = clearCallingIdentity(); 247 try { 248 if (mSyncManager == null) { 249 pw.println("SyncManager not available yet"); 250 } else { 251 mSyncManager.dump(fd, pw, dumpAll); 252 } 253 pw.println(); 254 pw.println("Observer tree:"); 255 synchronized (mRootNode) { 256 int[] counts = new int[2]; 257 final SparseIntArray pidCounts = new SparseIntArray(); 258 mRootNode.dumpLocked(fd, pw, args, "", " ", counts, pidCounts); 259 pw.println(); 260 ArrayList<Integer> sorted = new ArrayList<Integer>(); 261 for (int i=0; i<pidCounts.size(); i++) { 262 sorted.add(pidCounts.keyAt(i)); 263 } 264 Collections.sort(sorted, new Comparator<Integer>() { 265 @Override 266 public int compare(Integer lhs, Integer rhs) { 267 int lc = pidCounts.get(lhs); 268 int rc = pidCounts.get(rhs); 269 if (lc < rc) { 270 return 1; 271 } else if (lc > rc) { 272 return -1; 273 } 274 return 0; 275 } 276 277 }); 278 for (int i=0; i<sorted.size(); i++) { 279 int pid = sorted.get(i); 280 pw.print(" pid "); pw.print(pid); pw.print(": "); 281 pw.print(pidCounts.get(pid)); pw.println(" observers"); 282 } 283 pw.println(); 284 pw.increaseIndent(); 285 pw.print("Total number of nodes: "); pw.println(counts[0]); 286 pw.print("Total number of observers: "); pw.println(counts[1]); 287 288 sObserverDeathDispatcher.dump(pw); 289 pw.decreaseIndent(); 290 } 291 synchronized (sObserverLeakDetectedUid) { 292 pw.println(); 293 pw.print("Observer leaking UIDs: "); 294 pw.println(sObserverLeakDetectedUid.toString()); 295 } 296 297 synchronized (mCache) { 298 pw.println(); 299 pw.println("Cached content:"); 300 pw.increaseIndent(); 301 for (int i = 0; i < mCache.size(); i++) { 302 pw.println("User " + mCache.keyAt(i) + ":"); 303 pw.increaseIndent(); 304 pw.println(mCache.valueAt(i)); 305 pw.decreaseIndent(); 306 } 307 pw.decreaseIndent(); 308 } 309 } finally { 310 restoreCallingIdentity(identityToken); 311 } 312 } 313 ContentService(Context context, boolean factoryTest)314 /*package*/ ContentService(Context context, boolean factoryTest) { 315 mContext = context; 316 mFactoryTest = factoryTest; 317 318 // Let the package manager query for the sync adapters for a given authority 319 // as we grant default permissions to sync adapters for specific authorities. 320 final LegacyPermissionManagerInternal permissionManagerInternal = 321 LocalServices.getService(LegacyPermissionManagerInternal.class); 322 permissionManagerInternal.setSyncAdapterPackagesProvider((authority, userId) -> { 323 return getSyncAdapterPackagesForAuthorityAsUser(authority, userId); 324 }); 325 326 final IntentFilter packageFilter = new IntentFilter(); 327 packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 328 packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 329 packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 330 packageFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED); 331 packageFilter.addDataScheme("package"); 332 mContext.registerReceiverAsUser(mCacheReceiver, UserHandle.ALL, 333 packageFilter, null, null); 334 335 final IntentFilter localeFilter = new IntentFilter(); 336 localeFilter.addAction(Intent.ACTION_LOCALE_CHANGED); 337 mContext.registerReceiverAsUser(mCacheReceiver, UserHandle.ALL, 338 localeFilter, null, null); 339 340 mAccountManagerInternal = LocalServices.getService(AccountManagerInternal.class); 341 } 342 onBootPhase(int phase)343 void onBootPhase(int phase) { 344 switch (phase) { 345 case SystemService.PHASE_ACTIVITY_MANAGER_READY: 346 getSyncManager(); 347 break; 348 } 349 if (mSyncManager != null) { 350 mSyncManager.onBootPhase(phase); 351 } 352 } 353 354 /** 355 * Register a content observer tied to a specific user's view of the provider. 356 * @param userHandle the user whose view of the provider is to be observed. May be 357 * the calling user without requiring any permission, otherwise the caller needs to 358 * hold the INTERACT_ACROSS_USERS_FULL permission or hold a read uri grant to the uri. 359 * Pseudousers USER_ALL and USER_CURRENT are properly handled; all other pseudousers 360 * are forbidden. 361 */ 362 @Override registerContentObserver(Uri uri, boolean notifyForDescendants, IContentObserver observer, int userHandle, int targetSdkVersion)363 public void registerContentObserver(Uri uri, boolean notifyForDescendants, 364 IContentObserver observer, int userHandle, int targetSdkVersion) { 365 if (observer == null || uri == null) { 366 throw new IllegalArgumentException("You must pass a valid uri and observer"); 367 } 368 369 final int uid = Binder.getCallingUid(); 370 final int pid = Binder.getCallingPid(); 371 372 userHandle = handleIncomingUser(uri, pid, uid, 373 Intent.FLAG_GRANT_READ_URI_PERMISSION, true, userHandle); 374 375 final String msg = LocalServices.getService(ActivityManagerInternal.class) 376 .checkContentProviderAccess(uri.getAuthority(), userHandle); 377 if (msg != null) { 378 if (targetSdkVersion >= Build.VERSION_CODES.O) { 379 throw new SecurityException(msg); 380 } else { 381 if (msg.startsWith("Failed to find provider")) { 382 // Sigh, we need to quietly let apps targeting older API 383 // levels notify on non-existent providers. 384 } else { 385 Log.w(TAG, "Ignoring content changes for " + uri + " from " + uid + ": " + msg); 386 return; 387 } 388 } 389 } 390 391 synchronized (mRootNode) { 392 mRootNode.addObserverLocked(uri, observer, notifyForDescendants, mRootNode, 393 uid, pid, userHandle); 394 if (false) Log.v(TAG, "Registered observer " + observer + " at " + uri + 395 " with notifyForDescendants " + notifyForDescendants); 396 } 397 } 398 registerContentObserver(Uri uri, boolean notifyForDescendants, IContentObserver observer)399 public void registerContentObserver(Uri uri, boolean notifyForDescendants, 400 IContentObserver observer) { 401 registerContentObserver(uri, notifyForDescendants, observer, 402 UserHandle.getCallingUserId(), Build.VERSION_CODES.CUR_DEVELOPMENT); 403 } 404 405 @Override unregisterContentObserver(IContentObserver observer)406 public void unregisterContentObserver(IContentObserver observer) { 407 if (observer == null) { 408 throw new IllegalArgumentException("You must pass a valid observer"); 409 } 410 synchronized (mRootNode) { 411 mRootNode.removeObserverLocked(observer); 412 if (false) Log.v(TAG, "Unregistered observer " + observer); 413 } 414 } 415 416 /** 417 * Notify observers of a particular user's view of the provider. 418 * @param userHandle the user whose view of the provider is to be notified. May be 419 * the calling user without requiring any permission, otherwise the caller needs to 420 * hold the INTERACT_ACROSS_USERS_FULL permission or hold a write uri grant to the uri. 421 * Pseudousers USER_ALL and USER_CURRENT are properly interpreted; no other pseudousers are 422 * allowed. 423 */ 424 @Override notifyChange(Uri[] uris, IContentObserver observer, boolean observerWantsSelfNotifications, int flags, int userId, int targetSdkVersion, String callingPackage)425 public void notifyChange(Uri[] uris, IContentObserver observer, 426 boolean observerWantsSelfNotifications, int flags, int userId, 427 int targetSdkVersion, String callingPackage) { 428 if (DEBUG) { 429 Slog.d(TAG, "Notifying update of " + Arrays.toString(uris) + " for user " + userId 430 + ", observer " + observer + ", flags " + Integer.toHexString(flags)); 431 } 432 433 final int callingUid = Binder.getCallingUid(); 434 final int callingPid = Binder.getCallingPid(); 435 final int callingUserId = UserHandle.getCallingUserId(); 436 437 // Set of notification events that we need to dispatch 438 final ObserverCollector collector = new ObserverCollector(); 439 440 // Set of content provider authorities that we've validated the caller 441 // has access to, mapped to the package name hosting that provider 442 final ArrayMap<Pair<String, Integer>, String> validatedProviders = new ArrayMap<>(); 443 444 for (Uri uri : uris) { 445 // Validate that calling app has access to this provider 446 final int resolvedUserId = handleIncomingUser(uri, callingPid, callingUid, 447 Intent.FLAG_GRANT_WRITE_URI_PERMISSION, true, userId); 448 final Pair<String, Integer> provider = Pair.create(uri.getAuthority(), resolvedUserId); 449 if (!validatedProviders.containsKey(provider)) { 450 final String msg = LocalServices.getService(ActivityManagerInternal.class) 451 .checkContentProviderAccess(uri.getAuthority(), resolvedUserId); 452 if (msg != null) { 453 if (targetSdkVersion >= Build.VERSION_CODES.O) { 454 throw new SecurityException(msg); 455 } else { 456 if (msg.startsWith("Failed to find provider")) { 457 // Sigh, we need to quietly let apps targeting older API 458 // levels notify on non-existent providers. 459 } else { 460 Log.w(TAG, "Ignoring notify for " + uri + " from " 461 + callingUid + ": " + msg); 462 continue; 463 } 464 } 465 } 466 467 // Remember that we've validated this access 468 final String packageName = getProviderPackageName(uri, resolvedUserId); 469 validatedProviders.put(provider, packageName); 470 } 471 472 // No concerns raised above, so caller has access; let's collect the 473 // notifications that should be dispatched 474 synchronized (mRootNode) { 475 final int segmentCount = ObserverNode.countUriSegments(uri); 476 mRootNode.collectObserversLocked(uri, segmentCount, 0, observer, 477 observerWantsSelfNotifications, flags, resolvedUserId, collector); 478 } 479 } 480 481 final long token = clearCallingIdentity(); 482 try { 483 // Actually dispatch all the notifications we collected 484 collector.dispatch(); 485 486 final SyncManager syncManager = getSyncManager(); 487 for (int i = 0; i < validatedProviders.size(); i++) { 488 final String authority = validatedProviders.keyAt(i).first; 489 final int resolvedUserId = validatedProviders.keyAt(i).second; 490 final String packageName = validatedProviders.valueAt(i); 491 492 // Kick off sync adapters for any authorities we touched 493 if ((flags & ContentResolver.NOTIFY_SYNC_TO_NETWORK) != 0) { 494 syncManager.scheduleLocalSync(null /* all accounts */, callingUserId, 495 callingUid, 496 authority, getSyncExemptionForCaller(callingUid), 497 callingUid, callingPid, callingPackage); 498 } 499 500 // Invalidate caches for any authorities we touched 501 synchronized (mCache) { 502 for (Uri uri : uris) { 503 if (Objects.equals(uri.getAuthority(), authority)) { 504 invalidateCacheLocked(resolvedUserId, packageName, uri); 505 } 506 } 507 } 508 } 509 } finally { 510 Binder.restoreCallingIdentity(token); 511 } 512 } 513 checkUriPermission(Uri uri, int pid, int uid, int modeFlags, int userHandle)514 private int checkUriPermission(Uri uri, int pid, int uid, int modeFlags, int userHandle) { 515 try { 516 return ActivityManager.getService().checkUriPermission( 517 uri, pid, uid, modeFlags, userHandle, null); 518 } catch (RemoteException e) { 519 return PackageManager.PERMISSION_DENIED; 520 } 521 } 522 523 /** 524 * Collection of detected change notifications that should be delivered. 525 * <p> 526 * To help reduce Binder transaction overhead, this class clusters together 527 * multiple {@link Uri} where all other arguments are identical. 528 */ 529 @VisibleForTesting 530 public static class ObserverCollector { 531 private final ArrayMap<Key, List<Uri>> collected = new ArrayMap<>(); 532 533 private static class Key { 534 final IContentObserver observer; 535 final int uid; 536 final boolean selfChange; 537 final int flags; 538 final int userId; 539 Key(IContentObserver observer, int uid, boolean selfChange, int flags, int userId)540 Key(IContentObserver observer, int uid, boolean selfChange, int flags, int userId) { 541 this.observer = observer; 542 this.uid = uid; 543 this.selfChange = selfChange; 544 this.flags = flags; 545 this.userId = userId; 546 } 547 548 @Override equals(Object o)549 public boolean equals(Object o) { 550 if (!(o instanceof Key)) { 551 return false; 552 } 553 final Key other = (Key) o; 554 return Objects.equals(observer, other.observer) 555 && (uid == other.uid) 556 && (selfChange == other.selfChange) 557 && (flags == other.flags) 558 && (userId == other.userId); 559 } 560 561 @Override hashCode()562 public int hashCode() { 563 return Objects.hash(observer, uid, selfChange, flags, userId); 564 } 565 } 566 collect(IContentObserver observer, int uid, boolean selfChange, Uri uri, int flags, int userId)567 public void collect(IContentObserver observer, int uid, boolean selfChange, Uri uri, 568 int flags, int userId) { 569 final Key key = new Key(observer, uid, selfChange, flags, userId); 570 List<Uri> value = collected.get(key); 571 if (value == null) { 572 value = new ArrayList<>(); 573 collected.put(key, value); 574 } 575 value.add(uri); 576 } 577 dispatch()578 public void dispatch() { 579 for (int i = 0; i < collected.size(); i++) { 580 final Key key = collected.keyAt(i); 581 final List<Uri> value = collected.valueAt(i); 582 583 final Runnable task = () -> { 584 try { 585 key.observer.onChangeEtc(key.selfChange, 586 value.toArray(new Uri[value.size()]), key.flags, key.userId); 587 } catch (RemoteException ignored) { 588 } 589 }; 590 591 // Immediately dispatch notifications to foreground apps that 592 // are important to the user; all other background observers are 593 // delayed to avoid stampeding 594 final boolean noDelay = (key.flags & ContentResolver.NOTIFY_NO_DELAY) != 0; 595 final int procState = LocalServices.getService(ActivityManagerInternal.class) 596 .getUidProcessState(key.uid); 597 if (procState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND || noDelay) { 598 task.run(); 599 } else { 600 BackgroundThread.getHandler().postDelayed(task, BACKGROUND_OBSERVER_DELAY); 601 } 602 } 603 } 604 } 605 606 @Override requestSync(Account account, String authority, Bundle extras, String callingPackage)607 public void requestSync(Account account, String authority, Bundle extras, 608 String callingPackage) { 609 Bundle.setDefusable(extras, true); 610 ContentResolver.validateSyncExtrasBundle(extras); 611 int userId = UserHandle.getCallingUserId(); 612 final int callingUid = Binder.getCallingUid(); 613 final int callingPid = Binder.getCallingPid(); 614 615 if (!hasAccountAccess(true, account, callingUid)) { 616 return; 617 } 618 if (!hasAuthorityAccess(authority, callingUid, userId)) { 619 return; 620 } 621 622 validateExtras(callingUid, extras); 623 final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(callingUid, extras); 624 625 // This makes it so that future permission checks will be in the context of this 626 // process rather than the caller's process. We will restore this before returning. 627 final long identityToken = clearCallingIdentity(); 628 try { 629 getSyncManager().scheduleSync(account, userId, callingUid, authority, extras, 630 SyncStorageEngine.AuthorityInfo.UNDEFINED, 631 syncExemption, callingUid, callingPid, callingPackage); 632 } finally { 633 restoreCallingIdentity(identityToken); 634 } 635 } 636 637 /** 638 * Request a sync with a generic {@link android.content.SyncRequest} object. This will be 639 * either: 640 * periodic OR one-off sync. 641 * and 642 * anonymous OR provider sync. 643 * Depending on the request, we enqueue to suit in the SyncManager. 644 * @param request The request object. Validation of this object is done by its builder. 645 */ 646 @Override sync(SyncRequest request, String callingPackage)647 public void sync(SyncRequest request, String callingPackage) { 648 syncAsUser(request, UserHandle.getCallingUserId(), callingPackage); 649 } 650 clampPeriod(long period)651 private long clampPeriod(long period) { 652 long minPeriod = JobInfo.getMinPeriodMillis() / 1000; 653 if (period < minPeriod) { 654 Slog.w(TAG, "Requested poll frequency of " + period 655 + " seconds being rounded up to " + minPeriod + "s."); 656 period = minPeriod; 657 } 658 return period; 659 } 660 661 /** 662 * If the user id supplied is different to the calling user, the caller must hold the 663 * INTERACT_ACROSS_USERS_FULL permission. 664 */ 665 @Override syncAsUser(SyncRequest request, int userId, String callingPackage)666 public void syncAsUser(SyncRequest request, int userId, String callingPackage) { 667 enforceCrossUserPermission(userId, "no permission to request sync as user: " + userId); 668 669 final int callingUid = Binder.getCallingUid(); 670 final int callingPid = Binder.getCallingPid(); 671 if (!hasAccountAccess(true, request.getAccount(), callingUid)) { 672 return; 673 } 674 if (!hasAuthorityAccess(request.getProvider(), callingUid, userId)) { 675 return; 676 } 677 678 final Bundle extras = request.getBundle(); 679 validateExtras(callingUid, extras); 680 final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(callingUid, extras); 681 682 // This makes it so that future permission checks will be in the context of this 683 // process rather than the caller's process. We will restore this before returning. 684 final long identityToken = clearCallingIdentity(); 685 try { 686 long flextime = request.getSyncFlexTime(); 687 long runAtTime = request.getSyncRunTime(); 688 if (request.isPeriodic()) { 689 mContext.enforceCallingOrSelfPermission( 690 Manifest.permission.WRITE_SYNC_SETTINGS, 691 "no permission to write the sync settings"); 692 SyncStorageEngine.EndPoint info; 693 info = new SyncStorageEngine.EndPoint( 694 request.getAccount(), request.getProvider(), userId); 695 696 runAtTime = clampPeriod(runAtTime); 697 // Schedule periodic sync. 698 getSyncManager().updateOrAddPeriodicSync(info, runAtTime, 699 flextime, extras); 700 } else { 701 getSyncManager().scheduleSync( 702 request.getAccount(), userId, callingUid, request.getProvider(), extras, 703 SyncStorageEngine.AuthorityInfo.UNDEFINED, 704 syncExemption, callingUid, callingPid, callingPackage); 705 } 706 } finally { 707 restoreCallingIdentity(identityToken); 708 } 709 } 710 711 /** 712 * Clear all scheduled sync operations that match the uri and cancel the active sync 713 * if they match the authority and account, if they are present. 714 * 715 * @param account filter the pending and active syncs to cancel using this account, or null. 716 * @param authority filter the pending and active syncs to cancel using this authority, or 717 * null. 718 * @param cname cancel syncs running on this service, or null for provider/account. 719 */ 720 @Override cancelSync(Account account, String authority, ComponentName cname)721 public void cancelSync(Account account, String authority, ComponentName cname) { 722 cancelSyncAsUser(account, authority, cname, UserHandle.getCallingUserId()); 723 } 724 725 /** 726 * Clear all scheduled sync operations that match the uri and cancel the active sync 727 * if they match the authority and account, if they are present. 728 * 729 * <p> If the user id supplied is different to the calling user, the caller must hold the 730 * INTERACT_ACROSS_USERS_FULL permission. 731 * 732 * @param account filter the pending and active syncs to cancel using this account, or null. 733 * @param authority filter the pending and active syncs to cancel using this authority, or 734 * null. 735 * @param userId the user id for which to cancel sync operations. 736 * @param cname cancel syncs running on this service, or null for provider/account. 737 */ 738 @Override cancelSyncAsUser(Account account, String authority, ComponentName cname, int userId)739 public void cancelSyncAsUser(Account account, String authority, ComponentName cname, 740 int userId) { 741 if (authority != null && authority.length() == 0) { 742 throw new IllegalArgumentException("Authority must be non-empty"); 743 } 744 enforceCrossUserPermission(userId, 745 "no permission to modify the sync settings for user " + userId); 746 747 if (cname != null) { 748 Slog.e(TAG, "cname not null."); 749 return; 750 } 751 752 // This makes it so that future permission checks will be in the context of this 753 // process rather than the caller's process. We will restore this before returning. 754 final long identityToken = clearCallingIdentity(); 755 try { 756 SyncStorageEngine.EndPoint info; 757 info = new SyncStorageEngine.EndPoint(account, authority, userId); 758 getSyncManager().clearScheduledSyncOperations(info); 759 getSyncManager().cancelActiveSync(info, null /* all syncs for this adapter */, "API"); 760 } finally { 761 restoreCallingIdentity(identityToken); 762 } 763 } 764 765 @Override cancelRequest(SyncRequest request)766 public void cancelRequest(SyncRequest request) { 767 if (request.isPeriodic()) { 768 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, 769 "no permission to write the sync settings"); 770 } 771 772 final int callingUid = Binder.getCallingUid(); 773 Bundle extras = new Bundle(request.getBundle()); 774 validateExtras(callingUid, extras); 775 776 int userId = UserHandle.getCallingUserId(); 777 final long identityToken = clearCallingIdentity(); 778 try { 779 SyncStorageEngine.EndPoint info; 780 781 Account account = request.getAccount(); 782 String provider = request.getProvider(); 783 info = new SyncStorageEngine.EndPoint(account, provider, userId); 784 if (request.isPeriodic()) { 785 // Remove periodic sync. 786 getSyncManager().removePeriodicSync(info, extras, 787 "cancelRequest() by uid=" + callingUid); 788 } 789 // Cancel active syncs and clear pending syncs from the queue. 790 getSyncManager().cancelScheduledSyncOperation(info, extras); 791 getSyncManager().cancelActiveSync(info, extras, "API"); 792 } finally { 793 restoreCallingIdentity(identityToken); 794 } 795 } 796 797 /** 798 * Get information about the SyncAdapters that are known to the system. 799 * @return an array of SyncAdapters that have registered with the system 800 */ 801 @Override getSyncAdapterTypes()802 public SyncAdapterType[] getSyncAdapterTypes() { 803 return getSyncAdapterTypesAsUser(UserHandle.getCallingUserId()); 804 } 805 806 /** 807 * Get information about the SyncAdapters that are known to the system for a particular user. 808 * 809 * <p> If the user id supplied is different to the calling user, the caller must hold the 810 * INTERACT_ACROSS_USERS_FULL permission. 811 * 812 * @return an array of SyncAdapters that have registered with the system 813 */ 814 @Override getSyncAdapterTypesAsUser(int userId)815 public SyncAdapterType[] getSyncAdapterTypesAsUser(int userId) { 816 enforceCrossUserPermission(userId, 817 "no permission to read sync settings for user " + userId); 818 819 // This makes it so that future permission checks will be in the context of this 820 // process rather than the caller's process. We will restore this before returning. 821 final int callingUid = Binder.getCallingUid(); 822 final long identityToken = clearCallingIdentity(); 823 try { 824 return getSyncManager().getSyncAdapterTypes(callingUid, userId); 825 } finally { 826 restoreCallingIdentity(identityToken); 827 } 828 } 829 830 @Override getSyncAdapterPackagesForAuthorityAsUser(String authority, int userId)831 public String[] getSyncAdapterPackagesForAuthorityAsUser(String authority, int userId) { 832 enforceCrossUserPermission(userId, 833 "no permission to read sync settings for user " + userId); 834 835 // This makes it so that future permission checks will be in the context of this 836 // process rather than the caller's process. We will restore this before returning. 837 final int callingUid = Binder.getCallingUid(); 838 final long identityToken = clearCallingIdentity(); 839 try { 840 return getSyncManager().getSyncAdapterPackagesForAuthorityAsUser(authority, callingUid, 841 userId); 842 } finally { 843 restoreCallingIdentity(identityToken); 844 } 845 } 846 847 @Override 848 @Nullable getSyncAdapterPackageAsUser(@onNull String accountType, @NonNull String authority, @UserIdInt int userId)849 public String getSyncAdapterPackageAsUser(@NonNull String accountType, 850 @NonNull String authority, @UserIdInt int userId) { 851 enforceCrossUserPermission(userId, 852 "no permission to read sync settings for user " + userId); 853 854 final int callingUid = Binder.getCallingUid(); 855 final long identityToken = clearCallingIdentity(); 856 try { 857 return getSyncManager().getSyncAdapterPackageAsUser(accountType, authority, 858 callingUid, userId); 859 } finally { 860 restoreCallingIdentity(identityToken); 861 } 862 } 863 864 @Override getSyncAutomatically(Account account, String providerName)865 public boolean getSyncAutomatically(Account account, String providerName) { 866 return getSyncAutomaticallyAsUser(account, providerName, UserHandle.getCallingUserId()); 867 } 868 869 /** 870 * If the user id supplied is different to the calling user, the caller must hold the 871 * INTERACT_ACROSS_USERS_FULL permission. 872 */ 873 @Override getSyncAutomaticallyAsUser(Account account, String providerName, int userId)874 public boolean getSyncAutomaticallyAsUser(Account account, String providerName, int userId) { 875 enforceCrossUserPermission(userId, 876 "no permission to read the sync settings for user " + userId); 877 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, 878 "no permission to read the sync settings"); 879 880 final int callingUid = Binder.getCallingUid(); 881 if (!hasAccountAccess(true, account, callingUid)) { 882 return false; 883 } 884 if (!hasAuthorityAccess(providerName, callingUid, userId)) { 885 return false; 886 } 887 888 final long identityToken = clearCallingIdentity(); 889 try { 890 return getSyncManager().getSyncStorageEngine() 891 .getSyncAutomatically(account, userId, providerName); 892 } finally { 893 restoreCallingIdentity(identityToken); 894 } 895 } 896 897 @Override setSyncAutomatically(Account account, String providerName, boolean sync)898 public void setSyncAutomatically(Account account, String providerName, boolean sync) { 899 setSyncAutomaticallyAsUser(account, providerName, sync, UserHandle.getCallingUserId()); 900 } 901 902 @Override setSyncAutomaticallyAsUser(Account account, String providerName, boolean sync, int userId)903 public void setSyncAutomaticallyAsUser(Account account, String providerName, boolean sync, 904 int userId) { 905 if (TextUtils.isEmpty(providerName)) { 906 throw new IllegalArgumentException("Authority must be non-empty"); 907 } 908 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, 909 "no permission to write the sync settings"); 910 enforceCrossUserPermission(userId, 911 "no permission to modify the sync settings for user " + userId); 912 913 final int callingUid = Binder.getCallingUid(); 914 final int callingPid = Binder.getCallingPid(); 915 if (!hasAccountAccess(true, account, callingUid)) { 916 return; 917 } 918 if (!hasAuthorityAccess(providerName, callingUid, userId)) { 919 return; 920 } 921 922 final int syncExemptionFlag = getSyncExemptionForCaller(callingUid); 923 924 final long identityToken = clearCallingIdentity(); 925 try { 926 getSyncManager().getSyncStorageEngine().setSyncAutomatically(account, userId, 927 providerName, sync, syncExemptionFlag, callingUid, callingPid); 928 } finally { 929 restoreCallingIdentity(identityToken); 930 } 931 } 932 933 /** Old API. Schedule periodic sync with default flexMillis time. */ 934 @Override addPeriodicSync(Account account, String authority, Bundle extras, long pollFrequency)935 public void addPeriodicSync(Account account, String authority, Bundle extras, 936 long pollFrequency) { 937 Bundle.setDefusable(extras, true); 938 if (account == null) { 939 throw new IllegalArgumentException("Account must not be null"); 940 } 941 if (TextUtils.isEmpty(authority)) { 942 throw new IllegalArgumentException("Authority must not be empty."); 943 } 944 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, 945 "no permission to write the sync settings"); 946 947 final int callingUid = Binder.getCallingUid(); 948 final int userId = UserHandle.getCallingUserId(); 949 if (!hasAccountAccess(true, account, callingUid)) { 950 return; 951 } 952 if (!hasAuthorityAccess(authority, callingUid, userId)) { 953 return; 954 } 955 956 validateExtras(callingUid, extras); 957 958 pollFrequency = clampPeriod(pollFrequency); 959 long defaultFlex = SyncStorageEngine.calculateDefaultFlexTime(pollFrequency); 960 961 final long identityToken = clearCallingIdentity(); 962 try { 963 SyncStorageEngine.EndPoint info = 964 new SyncStorageEngine.EndPoint(account, authority, userId); 965 getSyncManager().updateOrAddPeriodicSync(info, pollFrequency, 966 defaultFlex, extras); 967 } finally { 968 restoreCallingIdentity(identityToken); 969 } 970 } 971 972 @Override removePeriodicSync(Account account, String authority, Bundle extras)973 public void removePeriodicSync(Account account, String authority, Bundle extras) { 974 Bundle.setDefusable(extras, true); 975 if (account == null) { 976 throw new IllegalArgumentException("Account must not be null"); 977 } 978 if (TextUtils.isEmpty(authority)) { 979 throw new IllegalArgumentException("Authority must not be empty"); 980 } 981 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, 982 "no permission to write the sync settings"); 983 984 final int callingUid = Binder.getCallingUid(); 985 final int userId = UserHandle.getCallingUserId(); 986 if (!hasAccountAccess(true, account, callingUid)) { 987 return; 988 } 989 if (!hasAuthorityAccess(authority, callingUid, userId)) { 990 return; 991 } 992 993 validateExtras(callingUid, extras); 994 995 final long identityToken = clearCallingIdentity(); 996 try { 997 getSyncManager().removePeriodicSync( 998 new SyncStorageEngine.EndPoint(account, authority, userId), 999 extras, "removePeriodicSync() by uid=" + callingUid); 1000 } finally { 1001 restoreCallingIdentity(identityToken); 1002 } 1003 } 1004 1005 @Override getPeriodicSyncs(Account account, String providerName, ComponentName cname)1006 public List<PeriodicSync> getPeriodicSyncs(Account account, String providerName, 1007 ComponentName cname) { 1008 if (account == null) { 1009 throw new IllegalArgumentException("Account must not be null"); 1010 } 1011 if (TextUtils.isEmpty(providerName)) { 1012 throw new IllegalArgumentException("Authority must not be empty"); 1013 } 1014 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, 1015 "no permission to read the sync settings"); 1016 1017 final int callingUid = Binder.getCallingUid(); 1018 final int userId = UserHandle.getCallingUserId(); 1019 if (!hasAccountAccess(true, account, callingUid)) { 1020 return new ArrayList<>(); // return a new empty list for consistent behavior 1021 } 1022 if (!hasAuthorityAccess(providerName, callingUid, userId)) { 1023 return new ArrayList<>(); 1024 } 1025 1026 final long identityToken = clearCallingIdentity(); 1027 try { 1028 return getSyncManager().getPeriodicSyncs( 1029 new SyncStorageEngine.EndPoint(account, providerName, userId)); 1030 } finally { 1031 restoreCallingIdentity(identityToken); 1032 } 1033 } 1034 1035 @Override getIsSyncable(Account account, String providerName)1036 public int getIsSyncable(Account account, String providerName) { 1037 return getIsSyncableAsUser(account, providerName, UserHandle.getCallingUserId()); 1038 } 1039 1040 /** 1041 * If the user id supplied is different to the calling user, the caller must hold the 1042 * INTERACT_ACROSS_USERS_FULL permission. 1043 */ 1044 @Override getIsSyncableAsUser(Account account, String providerName, int userId)1045 public int getIsSyncableAsUser(Account account, String providerName, int userId) { 1046 enforceCrossUserPermission(userId, 1047 "no permission to read the sync settings for user " + userId); 1048 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, 1049 "no permission to read the sync settings"); 1050 1051 final int callingUid = Binder.getCallingUid(); 1052 if (!hasAccountAccess(true, account, callingUid)) { 1053 return SyncStorageEngine.AuthorityInfo.NOT_SYNCABLE; // to keep behavior consistent 1054 } 1055 if (!hasAuthorityAccess(providerName, callingUid, userId)) { 1056 return SyncStorageEngine.AuthorityInfo.NOT_SYNCABLE; 1057 } 1058 1059 final long identityToken = clearCallingIdentity(); 1060 try { 1061 return getSyncManager().computeSyncable(account, userId, providerName, false, 1062 /*checkStoppedState=*/ false); 1063 } finally { 1064 restoreCallingIdentity(identityToken); 1065 } 1066 } 1067 1068 @Override setIsSyncable(Account account, String providerName, int syncable)1069 public void setIsSyncable(Account account, String providerName, int syncable) { 1070 setIsSyncableAsUser(account, providerName, syncable, UserHandle.getCallingUserId()); 1071 } 1072 1073 /** 1074 * @hide 1075 */ 1076 @Override setIsSyncableAsUser(Account account, String providerName, int syncable, int userId)1077 public void setIsSyncableAsUser(Account account, String providerName, int syncable, 1078 int userId) { 1079 if (TextUtils.isEmpty(providerName)) { 1080 throw new IllegalArgumentException("Authority must not be empty"); 1081 } 1082 enforceCrossUserPermission(userId, 1083 "no permission to set the sync settings for user " + userId); 1084 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, 1085 "no permission to write the sync settings"); 1086 1087 syncable = normalizeSyncable(syncable); 1088 final int callingUid = Binder.getCallingUid(); 1089 final int callingPid = Binder.getCallingPid(); 1090 if (!hasAccountAccess(true, account, callingUid)) { 1091 return; 1092 } 1093 if (!hasAuthorityAccess(providerName, callingUid, userId)) { 1094 return; 1095 } 1096 1097 final long identityToken = clearCallingIdentity(); 1098 try { 1099 getSyncManager().getSyncStorageEngine().setIsSyncable( 1100 account, userId, providerName, syncable, callingUid, callingPid); 1101 } finally { 1102 restoreCallingIdentity(identityToken); 1103 } 1104 } 1105 1106 @Override getMasterSyncAutomatically()1107 public boolean getMasterSyncAutomatically() { 1108 return getMasterSyncAutomaticallyAsUser(UserHandle.getCallingUserId()); 1109 } 1110 1111 /** 1112 * If the user id supplied is different to the calling user, the caller must hold the 1113 * INTERACT_ACROSS_USERS_FULL permission. 1114 */ 1115 @Override getMasterSyncAutomaticallyAsUser(int userId)1116 public boolean getMasterSyncAutomaticallyAsUser(int userId) { 1117 enforceCrossUserPermission(userId, 1118 "no permission to read the sync settings for user " + userId); 1119 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, 1120 "no permission to read the sync settings"); 1121 1122 final long identityToken = clearCallingIdentity(); 1123 try { 1124 return getSyncManager().getSyncStorageEngine().getMasterSyncAutomatically(userId); 1125 } finally { 1126 restoreCallingIdentity(identityToken); 1127 } 1128 } 1129 1130 @Override setMasterSyncAutomatically(boolean flag)1131 public void setMasterSyncAutomatically(boolean flag) { 1132 setMasterSyncAutomaticallyAsUser(flag, UserHandle.getCallingUserId()); 1133 } 1134 1135 @Override setMasterSyncAutomaticallyAsUser(boolean flag, int userId)1136 public void setMasterSyncAutomaticallyAsUser(boolean flag, int userId) { 1137 enforceCrossUserPermission(userId, 1138 "no permission to set the sync status for user " + userId); 1139 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, 1140 "no permission to write the sync settings"); 1141 1142 final int callingUid = Binder.getCallingUid(); 1143 final int callingPid = Binder.getCallingPid(); 1144 1145 final long identityToken = clearCallingIdentity(); 1146 try { 1147 getSyncManager().getSyncStorageEngine().setMasterSyncAutomatically(flag, userId, 1148 getSyncExemptionForCaller(callingUid), callingUid, callingPid); 1149 } finally { 1150 restoreCallingIdentity(identityToken); 1151 } 1152 } 1153 1154 @android.annotation.EnforcePermission(android.Manifest.permission.READ_SYNC_STATS) 1155 @Override isSyncActive(Account account, String authority, ComponentName cname)1156 public boolean isSyncActive(Account account, String authority, ComponentName cname) { 1157 isSyncActive_enforcePermission(); 1158 1159 final int callingUid = Binder.getCallingUid(); 1160 final int userId = UserHandle.getCallingUserId(); 1161 if (!hasAccountAccess(true, account, callingUid)) { 1162 return false; 1163 } 1164 if (!hasAuthorityAccess(authority, callingUid, userId)) { 1165 return false; 1166 } 1167 1168 final long identityToken = clearCallingIdentity(); 1169 try { 1170 return getSyncManager().getSyncStorageEngine().isSyncActive( 1171 new SyncStorageEngine.EndPoint(account, authority, userId)); 1172 } finally { 1173 restoreCallingIdentity(identityToken); 1174 } 1175 } 1176 1177 @Override getCurrentSyncs()1178 public List<SyncInfo> getCurrentSyncs() { 1179 return getCurrentSyncsAsUser(UserHandle.getCallingUserId()); 1180 } 1181 1182 /** 1183 * If the user id supplied is different to the calling user, the caller must hold the 1184 * INTERACT_ACROSS_USERS_FULL permission. 1185 */ 1186 @Override getCurrentSyncsAsUser(int userId)1187 public List<SyncInfo> getCurrentSyncsAsUser(int userId) { 1188 enforceCrossUserPermission(userId, 1189 "no permission to read the sync settings for user " + userId); 1190 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS, 1191 "no permission to read the sync stats"); 1192 1193 final boolean canAccessAccounts = 1194 mContext.checkCallingOrSelfPermission(Manifest.permission.GET_ACCOUNTS) 1195 == PackageManager.PERMISSION_GRANTED; 1196 final List<SyncInfo> results; 1197 final int callingUid = Binder.getCallingUid(); 1198 final long identityToken = clearCallingIdentity(); 1199 try { 1200 results = getSyncManager().getSyncStorageEngine() 1201 .getCurrentSyncsCopy(userId, canAccessAccounts); 1202 } finally { 1203 restoreCallingIdentity(identityToken); 1204 } 1205 results.removeIf(i -> !hasAuthorityAccess(i.authority, callingUid, userId)); 1206 return results; 1207 } 1208 1209 @Override getSyncStatus(Account account, String authority, ComponentName cname)1210 public SyncStatusInfo getSyncStatus(Account account, String authority, ComponentName cname) { 1211 return getSyncStatusAsUser(account, authority, cname, UserHandle.getCallingUserId()); 1212 } 1213 1214 /** 1215 * If the user id supplied is different to the calling user, the caller must hold the 1216 * INTERACT_ACROSS_USERS_FULL permission. 1217 */ 1218 @Override 1219 @Nullable getSyncStatusAsUser(Account account, String authority, ComponentName cname, int userId)1220 public SyncStatusInfo getSyncStatusAsUser(Account account, String authority, 1221 ComponentName cname, int userId) { 1222 if (TextUtils.isEmpty(authority)) { 1223 throw new IllegalArgumentException("Authority must not be empty"); 1224 } 1225 1226 enforceCrossUserPermission(userId, 1227 "no permission to read the sync stats for user " + userId); 1228 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS, 1229 "no permission to read the sync stats"); 1230 1231 final int callingUid = Binder.getCallingUid(); 1232 if (!hasAccountAccess(true, account, callingUid)) { 1233 return null; 1234 } 1235 if (!hasAuthorityAccess(authority, callingUid, userId)) { 1236 return null; 1237 } 1238 1239 final long identityToken = clearCallingIdentity(); 1240 try { 1241 SyncStorageEngine.EndPoint info; 1242 if (!(account == null || authority == null)) { 1243 info = new SyncStorageEngine.EndPoint(account, authority, userId); 1244 } else { 1245 throw new IllegalArgumentException("Must call sync status with valid authority"); 1246 } 1247 return getSyncManager().getSyncStorageEngine().getStatusByAuthority(info); 1248 } finally { 1249 restoreCallingIdentity(identityToken); 1250 } 1251 } 1252 1253 @Override isSyncPending(Account account, String authority, ComponentName cname)1254 public boolean isSyncPending(Account account, String authority, ComponentName cname) { 1255 return isSyncPendingAsUser(account, authority, cname, UserHandle.getCallingUserId()); 1256 } 1257 1258 @android.annotation.EnforcePermission(android.Manifest.permission.READ_SYNC_STATS) 1259 @Override isSyncPendingAsUser(Account account, String authority, ComponentName cname, int userId)1260 public boolean isSyncPendingAsUser(Account account, String authority, ComponentName cname, 1261 int userId) { 1262 isSyncPendingAsUser_enforcePermission(); 1263 enforceCrossUserPermission(userId, 1264 "no permission to retrieve the sync settings for user " + userId); 1265 1266 final int callingUid = Binder.getCallingUid(); 1267 if (!hasAccountAccess(true, account, callingUid)) { 1268 return false; 1269 } 1270 if (!hasAuthorityAccess(authority, callingUid, userId)) { 1271 return false; 1272 } 1273 1274 final long identityToken = clearCallingIdentity(); 1275 try { 1276 SyncStorageEngine.EndPoint info; 1277 if (!(account == null || authority == null)) { 1278 info = new SyncStorageEngine.EndPoint(account, authority, userId); 1279 } else { 1280 throw new IllegalArgumentException("Invalid authority specified"); 1281 } 1282 return getSyncManager().getSyncStorageEngine().isSyncPending(info); 1283 } finally { 1284 restoreCallingIdentity(identityToken); 1285 } 1286 } 1287 1288 @Override addStatusChangeListener(int mask, ISyncStatusObserver callback)1289 public void addStatusChangeListener(int mask, ISyncStatusObserver callback) { 1290 final int callingUid = Binder.getCallingUid(); 1291 final long identityToken = clearCallingIdentity(); 1292 try { 1293 if (callback != null) { 1294 getSyncManager().getSyncStorageEngine().addStatusChangeListener( 1295 mask, callingUid, callback); 1296 } 1297 } finally { 1298 restoreCallingIdentity(identityToken); 1299 } 1300 } 1301 1302 @Override removeStatusChangeListener(ISyncStatusObserver callback)1303 public void removeStatusChangeListener(ISyncStatusObserver callback) { 1304 final long identityToken = clearCallingIdentity(); 1305 try { 1306 if (callback != null) { 1307 getSyncManager().getSyncStorageEngine().removeStatusChangeListener(callback); 1308 } 1309 } finally { 1310 restoreCallingIdentity(identityToken); 1311 } 1312 } 1313 getProviderPackageName(Uri uri, int userId)1314 private @Nullable String getProviderPackageName(Uri uri, int userId) { 1315 final ProviderInfo pi = mContext.getPackageManager().resolveContentProviderAsUser( 1316 uri.getAuthority(), 0, userId); 1317 return (pi != null) ? pi.packageName : null; 1318 } 1319 1320 @GuardedBy("mCache") findOrCreateCacheLocked(int userId, String providerPackageName)1321 private ArrayMap<Pair<String, Uri>, Bundle> findOrCreateCacheLocked(int userId, 1322 String providerPackageName) { 1323 ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>> userCache = mCache.get(userId); 1324 if (userCache == null) { 1325 userCache = new ArrayMap<>(); 1326 mCache.put(userId, userCache); 1327 } 1328 ArrayMap<Pair<String, Uri>, Bundle> packageCache = userCache.get(providerPackageName); 1329 if (packageCache == null) { 1330 packageCache = new ArrayMap<>(); 1331 userCache.put(providerPackageName, packageCache); 1332 } 1333 return packageCache; 1334 } 1335 1336 @GuardedBy("mCache") invalidateCacheLocked(int userId, String providerPackageName, Uri uri)1337 private void invalidateCacheLocked(int userId, String providerPackageName, Uri uri) { 1338 ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>> userCache = mCache.get(userId); 1339 if (userCache == null) return; 1340 1341 ArrayMap<Pair<String, Uri>, Bundle> packageCache = userCache.get(providerPackageName); 1342 if (packageCache == null) return; 1343 1344 if (uri != null) { 1345 for (int i = 0; i < packageCache.size();) { 1346 final Pair<String, Uri> key = packageCache.keyAt(i); 1347 if (key.second != null && key.second.toString().startsWith(uri.toString())) { 1348 if (DEBUG) Slog.d(TAG, "Invalidating cache for key " + key); 1349 packageCache.removeAt(i); 1350 } else { 1351 i++; 1352 } 1353 } 1354 } else { 1355 if (DEBUG) Slog.d(TAG, "Invalidating cache for package " + providerPackageName); 1356 packageCache.clear(); 1357 } 1358 } 1359 1360 @Override 1361 @RequiresPermission(android.Manifest.permission.CACHE_CONTENT) putCache(String packageName, Uri key, Bundle value, int userId)1362 public void putCache(String packageName, Uri key, Bundle value, int userId) { 1363 Bundle.setDefusable(value, true); 1364 enforceNonFullCrossUserPermission(userId, TAG); 1365 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CACHE_CONTENT, TAG); 1366 mContext.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(), 1367 packageName); 1368 1369 final String providerPackageName = getProviderPackageName(key, userId); 1370 final Pair<String, Uri> fullKey = Pair.create(packageName, key); 1371 1372 synchronized (mCache) { 1373 final ArrayMap<Pair<String, Uri>, Bundle> cache = findOrCreateCacheLocked(userId, 1374 providerPackageName); 1375 if (value != null) { 1376 cache.put(fullKey, value); 1377 } else { 1378 cache.remove(fullKey); 1379 } 1380 } 1381 } 1382 1383 @Override 1384 @RequiresPermission(android.Manifest.permission.CACHE_CONTENT) getCache(String packageName, Uri key, int userId)1385 public Bundle getCache(String packageName, Uri key, int userId) { 1386 enforceNonFullCrossUserPermission(userId, TAG); 1387 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CACHE_CONTENT, TAG); 1388 mContext.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(), 1389 packageName); 1390 1391 final String providerPackageName = getProviderPackageName(key, userId); 1392 final Pair<String, Uri> fullKey = Pair.create(packageName, key); 1393 1394 synchronized (mCache) { 1395 final ArrayMap<Pair<String, Uri>, Bundle> cache = findOrCreateCacheLocked(userId, 1396 providerPackageName); 1397 return cache.get(fullKey); 1398 } 1399 } 1400 handleIncomingUser(Uri uri, int pid, int uid, int modeFlags, boolean allowNonFull, int userId)1401 private int handleIncomingUser(Uri uri, int pid, int uid, int modeFlags, boolean allowNonFull, 1402 int userId) { 1403 if (userId == UserHandle.USER_CURRENT) { 1404 userId = ActivityManager.getCurrentUser(); 1405 } 1406 1407 if (userId == UserHandle.USER_ALL) { 1408 mContext.enforceCallingOrSelfPermission( 1409 Manifest.permission.INTERACT_ACROSS_USERS_FULL, "No access to " + uri); 1410 } else if (userId < 0) { 1411 throw new IllegalArgumentException("Invalid user: " + userId); 1412 } else if (userId != UserHandle.getCallingUserId()) { 1413 if (checkUriPermission(uri, pid, uid, modeFlags, 1414 userId) != PackageManager.PERMISSION_GRANTED) { 1415 boolean allow = false; 1416 if (mContext.checkCallingOrSelfPermission( 1417 Manifest.permission.INTERACT_ACROSS_USERS_FULL) 1418 == PackageManager.PERMISSION_GRANTED) { 1419 allow = true; 1420 } else if (allowNonFull && mContext.checkCallingOrSelfPermission( 1421 Manifest.permission.INTERACT_ACROSS_USERS) 1422 == PackageManager.PERMISSION_GRANTED) { 1423 allow = true; 1424 } 1425 if (!allow) { 1426 final String permissions = allowNonFull 1427 ? (Manifest.permission.INTERACT_ACROSS_USERS_FULL + " or " + 1428 Manifest.permission.INTERACT_ACROSS_USERS) 1429 : Manifest.permission.INTERACT_ACROSS_USERS_FULL; 1430 throw new SecurityException("No access to " + uri + ": neither user " + uid 1431 + " nor current process has " + permissions); 1432 } 1433 } 1434 } 1435 1436 return userId; 1437 } 1438 1439 /** 1440 * Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS_FULL 1441 * permission, if the userHandle is not for the caller. 1442 * 1443 * @param userHandle the user handle of the user we want to act on behalf of. 1444 * @param message the message to log on security exception. 1445 */ enforceCrossUserPermission(int userHandle, String message)1446 private void enforceCrossUserPermission(int userHandle, String message) { 1447 final int callingUser = UserHandle.getCallingUserId(); 1448 if (callingUser != userHandle) { 1449 mContext.enforceCallingOrSelfPermission( 1450 Manifest.permission.INTERACT_ACROSS_USERS_FULL, message); 1451 } 1452 } 1453 1454 /** 1455 * Checks if the request is from the system or an app that has {@code INTERACT_ACROSS_USERS} or 1456 * {@code INTERACT_ACROSS_USERS_FULL} permission, if the {@code userHandle} is not for the 1457 * caller. 1458 * 1459 * @param userHandle the user handle of the user we want to act on behalf of. 1460 * @param message the message to log on security exception. 1461 */ enforceNonFullCrossUserPermission(int userHandle, String message)1462 private void enforceNonFullCrossUserPermission(int userHandle, String message) { 1463 final int callingUser = UserHandle.getCallingUserId(); 1464 if (callingUser == userHandle) { 1465 return; 1466 } 1467 1468 int interactAcrossUsersState = mContext.checkCallingOrSelfPermission( 1469 Manifest.permission.INTERACT_ACROSS_USERS); 1470 if (interactAcrossUsersState == PERMISSION_GRANTED) { 1471 return; 1472 } 1473 1474 mContext.enforceCallingOrSelfPermission( 1475 Manifest.permission.INTERACT_ACROSS_USERS_FULL, message); 1476 } 1477 1478 /** 1479 * Checks to see if the given account is accessible by the provided uid. 1480 * 1481 * @param checkCompatFlag whether to check if the ACCOUNT_ACCESS_CHECK_CHANGE_ID flag is enabled 1482 * @param account the account trying to be accessed 1483 * @param uid the uid trying to access the account 1484 * @return {@code true} if the account is accessible by the given uid, {@code false} otherwise 1485 */ hasAccountAccess(boolean checkCompatFlag, Account account, int uid)1486 private boolean hasAccountAccess(boolean checkCompatFlag, Account account, int uid) { 1487 if (account == null) { 1488 // If the account is null, it means to check for all accounts hence skip the check here. 1489 return true; 1490 } 1491 if (checkCompatFlag 1492 && !CompatChanges.isChangeEnabled(ACCOUNT_ACCESS_CHECK_CHANGE_ID, uid)) { 1493 return true; 1494 } 1495 1496 final long identityToken = clearCallingIdentity(); 1497 try { 1498 return mAccountManagerInternal.hasAccountAccess(account, uid); 1499 } finally { 1500 restoreCallingIdentity(identityToken); 1501 } 1502 } 1503 1504 /** 1505 * Checks to see if the given authority is accessible by the caller. 1506 * 1507 * @param authority the authority to be accessed 1508 * @param uid the uid trying to access the authority 1509 * @param userId the user id for which to access the authority 1510 * @return {@code true} if the authority is accessible by the caller, {@code false} otherwise 1511 */ hasAuthorityAccess(@ullable String authority, int uid, @UserIdInt int userId)1512 private boolean hasAuthorityAccess(@Nullable String authority, int uid, @UserIdInt int userId) { 1513 if (TextUtils.isEmpty(authority)) { 1514 return true; 1515 } 1516 if (!CompatChanges.isChangeEnabled(AUTHORITY_ACCESS_CHECK_CHANGE_ID, uid)) { 1517 return true; 1518 } 1519 // Since #getSyncAdapterPackagesForAuthorityAsUser would filter out the packages 1520 // that aren't visible to the callers, using this to check if the given authority 1521 // is accessible by the callers. 1522 final String[] syncAdapterPackages = 1523 getSyncAdapterPackagesForAuthorityAsUser(authority, userId); 1524 return !ArrayUtils.isEmpty(syncAdapterPackages); 1525 } 1526 1527 normalizeSyncable(int syncable)1528 private static int normalizeSyncable(int syncable) { 1529 if (syncable > 0) { 1530 return SyncStorageEngine.AuthorityInfo.SYNCABLE; 1531 } else if (syncable == 0) { 1532 return SyncStorageEngine.AuthorityInfo.NOT_SYNCABLE; 1533 } 1534 return SyncStorageEngine.AuthorityInfo.UNDEFINED; 1535 } 1536 validateExtras(int callingUid, Bundle extras)1537 private void validateExtras(int callingUid, Bundle extras) { 1538 if (extras.containsKey(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG)) { 1539 switch (callingUid) { 1540 case Process.ROOT_UID: 1541 case Process.SHELL_UID: 1542 case Process.SYSTEM_UID: 1543 break; // Okay 1544 default: 1545 final String msg = "Invalid extras specified."; 1546 Log.w(TAG, msg + " requestsync -f/-F needs to run on 'adb shell'"); 1547 throw new SecurityException(msg); 1548 } 1549 } 1550 } 1551 1552 @SyncExemption getSyncExemptionForCaller(int callingUid)1553 private int getSyncExemptionForCaller(int callingUid) { 1554 return getSyncExemptionAndCleanUpExtrasForCaller(callingUid, null); 1555 } 1556 1557 @SyncExemption getSyncExemptionAndCleanUpExtrasForCaller(int callingUid, Bundle extras)1558 private int getSyncExemptionAndCleanUpExtrasForCaller(int callingUid, Bundle extras) { 1559 if (extras != null) { 1560 final int exemption = 1561 extras.getInt(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG, -1); 1562 1563 // Need to remove the virtual extra. 1564 extras.remove(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG); 1565 if (exemption != -1) { 1566 return exemption; 1567 } 1568 } 1569 final ActivityManagerInternal ami = 1570 LocalServices.getService(ActivityManagerInternal.class); 1571 if (ami == null) { 1572 return ContentResolver.SYNC_EXEMPTION_NONE; 1573 } 1574 final int procState = ami.getUidProcessState(callingUid); 1575 final boolean isUidActive = ami.isUidActive(callingUid); 1576 1577 // Providers bound by a TOP app will get PROCESS_STATE_BOUND_TOP, so include those as well 1578 if (procState <= ActivityManager.PROCESS_STATE_TOP 1579 || procState == ActivityManager.PROCESS_STATE_BOUND_TOP) { 1580 return ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP; 1581 } 1582 if (procState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND || isUidActive) { 1583 FrameworkStatsLog.write(FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED, 1584 callingUid, getProcStateForStatsd(procState), isUidActive, 1585 getRestrictionLevelForStatsd(ami.getRestrictionLevel(callingUid))); 1586 return ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET; 1587 } 1588 return ContentResolver.SYNC_EXEMPTION_NONE; 1589 } 1590 getProcStateForStatsd(int procState)1591 private int getProcStateForStatsd(int procState) { 1592 switch (procState) { 1593 case ActivityManager.PROCESS_STATE_UNKNOWN: 1594 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__UNKNOWN; 1595 case ActivityManager.PROCESS_STATE_PERSISTENT: 1596 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__PERSISTENT; 1597 case ActivityManager.PROCESS_STATE_PERSISTENT_UI: 1598 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__PERSISTENT_UI; 1599 case ActivityManager.PROCESS_STATE_TOP: 1600 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__TOP; 1601 case ActivityManager.PROCESS_STATE_BOUND_TOP: 1602 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__BOUND_TOP; 1603 case ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE: 1604 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__FOREGROUND_SERVICE; 1605 case ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE: 1606 return FrameworkStatsLog 1607 .SYNC_EXEMPTION_OCCURRED__PROC_STATE__BOUND_FOREGROUND_SERVICE; 1608 case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND: 1609 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__IMPORTANT_FOREGROUND; 1610 case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND: 1611 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__IMPORTANT_BACKGROUND; 1612 case ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND: 1613 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__TRANSIENT_BACKGROUND; 1614 case ActivityManager.PROCESS_STATE_BACKUP: 1615 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__BACKUP; 1616 case ActivityManager.PROCESS_STATE_SERVICE: 1617 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__SERVICE; 1618 case ActivityManager.PROCESS_STATE_RECEIVER: 1619 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__RECEIVER; 1620 case ActivityManager.PROCESS_STATE_TOP_SLEEPING: 1621 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__TOP_SLEEPING; 1622 case ActivityManager.PROCESS_STATE_HEAVY_WEIGHT: 1623 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__HEAVY_WEIGHT; 1624 case ActivityManager.PROCESS_STATE_LAST_ACTIVITY: 1625 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__LAST_ACTIVITY; 1626 case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY: 1627 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__CACHED_ACTIVITY; 1628 case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT: 1629 return FrameworkStatsLog 1630 .SYNC_EXEMPTION_OCCURRED__PROC_STATE__CACHED_ACTIVITY_CLIENT; 1631 case ActivityManager.PROCESS_STATE_CACHED_RECENT: 1632 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__CACHED_RECENT; 1633 case ActivityManager.PROCESS_STATE_CACHED_EMPTY: 1634 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__CACHED_EMPTY; 1635 default: 1636 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__UNKNOWN; 1637 } 1638 } 1639 getRestrictionLevelForStatsd(@estrictionLevel int level)1640 private int getRestrictionLevelForStatsd(@RestrictionLevel int level) { 1641 switch (level) { 1642 case ActivityManager.RESTRICTION_LEVEL_UNKNOWN: 1643 return AppBackgroundRestrictionsInfo.LEVEL_UNKNOWN; 1644 case ActivityManager.RESTRICTION_LEVEL_UNRESTRICTED: 1645 return AppBackgroundRestrictionsInfo.LEVEL_UNRESTRICTED; 1646 case ActivityManager.RESTRICTION_LEVEL_EXEMPTED: 1647 return AppBackgroundRestrictionsInfo.LEVEL_EXEMPTED; 1648 case ActivityManager.RESTRICTION_LEVEL_ADAPTIVE_BUCKET: 1649 return AppBackgroundRestrictionsInfo.LEVEL_ADAPTIVE_BUCKET; 1650 case ActivityManager.RESTRICTION_LEVEL_RESTRICTED_BUCKET: 1651 return AppBackgroundRestrictionsInfo.LEVEL_RESTRICTED_BUCKET; 1652 case ActivityManager.RESTRICTION_LEVEL_BACKGROUND_RESTRICTED: 1653 return AppBackgroundRestrictionsInfo.LEVEL_BACKGROUND_RESTRICTED; 1654 case ActivityManager.RESTRICTION_LEVEL_FORCE_STOPPED: 1655 return AppBackgroundRestrictionsInfo.LEVEL_HIBERNATION; 1656 default: 1657 return AppBackgroundRestrictionsInfo.LEVEL_UNKNOWN; 1658 } 1659 } 1660 1661 /** {@hide} */ 1662 @VisibleForTesting 1663 public static final class ObserverNode { 1664 private class ObserverEntry implements IBinder.DeathRecipient { 1665 public final IContentObserver observer; 1666 public final int uid; 1667 public final int pid; 1668 public final boolean notifyForDescendants; 1669 private final int userHandle; 1670 private final Object observersLock; 1671 ObserverEntry(IContentObserver o, boolean n, Object observersLock, int _uid, int _pid, int _userHandle, Uri uri)1672 public ObserverEntry(IContentObserver o, boolean n, Object observersLock, 1673 int _uid, int _pid, int _userHandle, Uri uri) { 1674 this.observersLock = observersLock; 1675 observer = o; 1676 uid = _uid; 1677 pid = _pid; 1678 userHandle = _userHandle; 1679 notifyForDescendants = n; 1680 1681 final int entries = sObserverDeathDispatcher.linkToDeath(observer, this); 1682 if (entries == -1) { 1683 binderDied(); 1684 } else if (entries == TOO_MANY_OBSERVERS_THRESHOLD) { 1685 boolean alreadyDetected; 1686 1687 synchronized (sObserverLeakDetectedUid) { 1688 alreadyDetected = sObserverLeakDetectedUid.contains(uid); 1689 if (!alreadyDetected) { 1690 sObserverLeakDetectedUid.add(uid); 1691 } 1692 } 1693 if (!alreadyDetected) { 1694 String caller = null; 1695 try { 1696 caller = ArrayUtils.firstOrNull(AppGlobals.getPackageManager() 1697 .getPackagesForUid(uid)); 1698 } catch (RemoteException ignore) { 1699 } 1700 Slog.wtf(TAG, "Observer registered too many times. Leak? cpid=" + pid 1701 + " cuid=" + uid 1702 + " cpkg=" + caller 1703 + " url=" + uri); 1704 } 1705 } 1706 1707 } 1708 1709 @Override binderDied()1710 public void binderDied() { 1711 synchronized (observersLock) { 1712 removeObserverLocked(observer); 1713 } 1714 } 1715 dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args, String name, String prefix, SparseIntArray pidCounts)1716 public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args, 1717 String name, String prefix, SparseIntArray pidCounts) { 1718 pidCounts.put(pid, pidCounts.get(pid)+1); 1719 pw.print(prefix); pw.print(name); pw.print(": pid="); 1720 pw.print(pid); pw.print(" uid="); 1721 pw.print(uid); pw.print(" user="); 1722 pw.print(userHandle); pw.print(" target="); 1723 pw.println(Integer.toHexString(System.identityHashCode( 1724 observer != null ? observer.asBinder() : null))); 1725 } 1726 } 1727 1728 private String mName; 1729 private ArrayList<ObserverNode> mChildren = new ArrayList<ObserverNode>(); 1730 private ArrayList<ObserverEntry> mObservers = new ArrayList<ObserverEntry>(); 1731 ObserverNode(String name)1732 public ObserverNode(String name) { 1733 mName = name; 1734 } 1735 dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args, String name, String prefix, int[] counts, SparseIntArray pidCounts)1736 public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args, 1737 String name, String prefix, int[] counts, SparseIntArray pidCounts) { 1738 String innerName = null; 1739 if (mObservers.size() > 0) { 1740 if ("".equals(name)) { 1741 innerName = mName; 1742 } else { 1743 innerName = name + "/" + mName; 1744 } 1745 for (int i=0; i<mObservers.size(); i++) { 1746 counts[1]++; 1747 mObservers.get(i).dumpLocked(fd, pw, args, innerName, prefix, 1748 pidCounts); 1749 } 1750 } 1751 if (mChildren.size() > 0) { 1752 if (innerName == null) { 1753 if ("".equals(name)) { 1754 innerName = mName; 1755 } else { 1756 innerName = name + "/" + mName; 1757 } 1758 } 1759 for (int i=0; i<mChildren.size(); i++) { 1760 counts[0]++; 1761 mChildren.get(i).dumpLocked(fd, pw, args, innerName, prefix, 1762 counts, pidCounts); 1763 } 1764 } 1765 } 1766 getUriSegment(Uri uri, int index)1767 public static String getUriSegment(Uri uri, int index) { 1768 if (uri != null) { 1769 if (index == 0) { 1770 return uri.getAuthority(); 1771 } else { 1772 return uri.getPathSegments().get(index - 1); 1773 } 1774 } else { 1775 return null; 1776 } 1777 } 1778 countUriSegments(Uri uri)1779 public static int countUriSegments(Uri uri) { 1780 if (uri == null) { 1781 return 0; 1782 } 1783 return uri.getPathSegments().size() + 1; 1784 } 1785 1786 // Invariant: userHandle is either a hard user number or is USER_ALL addObserverLocked(Uri uri, IContentObserver observer, boolean notifyForDescendants, Object observersLock, int uid, int pid, int userHandle)1787 public void addObserverLocked(Uri uri, IContentObserver observer, 1788 boolean notifyForDescendants, Object observersLock, 1789 int uid, int pid, int userHandle) { 1790 addObserverLocked(uri, 0, observer, notifyForDescendants, observersLock, 1791 uid, pid, userHandle); 1792 } 1793 addObserverLocked(Uri uri, int index, IContentObserver observer, boolean notifyForDescendants, Object observersLock, int uid, int pid, int userHandle)1794 private void addObserverLocked(Uri uri, int index, IContentObserver observer, 1795 boolean notifyForDescendants, Object observersLock, 1796 int uid, int pid, int userHandle) { 1797 // If this is the leaf node add the observer 1798 if (index == countUriSegments(uri)) { 1799 mObservers.add(new ObserverEntry(observer, notifyForDescendants, observersLock, 1800 uid, pid, userHandle, uri)); 1801 return; 1802 } 1803 1804 // Look to see if the proper child already exists 1805 String segment = getUriSegment(uri, index); 1806 if (segment == null) { 1807 throw new IllegalArgumentException("Invalid Uri (" + uri + ") used for observer"); 1808 } 1809 int N = mChildren.size(); 1810 for (int i = 0; i < N; i++) { 1811 ObserverNode node = mChildren.get(i); 1812 if (node.mName.equals(segment)) { 1813 node.addObserverLocked(uri, index + 1, observer, notifyForDescendants, 1814 observersLock, uid, pid, userHandle); 1815 return; 1816 } 1817 } 1818 1819 // No child found, create one 1820 ObserverNode node = new ObserverNode(segment); 1821 mChildren.add(node); 1822 node.addObserverLocked(uri, index + 1, observer, notifyForDescendants, 1823 observersLock, uid, pid, userHandle); 1824 } 1825 removeObserverLocked(IContentObserver observer)1826 public boolean removeObserverLocked(IContentObserver observer) { 1827 int size = mChildren.size(); 1828 for (int i = 0; i < size; i++) { 1829 boolean empty = mChildren.get(i).removeObserverLocked(observer); 1830 if (empty) { 1831 mChildren.remove(i); 1832 i--; 1833 size--; 1834 } 1835 } 1836 1837 IBinder observerBinder = observer.asBinder(); 1838 size = mObservers.size(); 1839 for (int i = 0; i < size; i++) { 1840 ObserverEntry entry = mObservers.get(i); 1841 if (entry.observer.asBinder() == observerBinder) { 1842 mObservers.remove(i); 1843 // We no longer need to listen for death notifications. Remove it. 1844 sObserverDeathDispatcher.unlinkToDeath(observer, entry); 1845 break; 1846 } 1847 } 1848 1849 if (mChildren.size() == 0 && mObservers.size() == 0) { 1850 return true; 1851 } 1852 return false; 1853 } 1854 collectMyObserversLocked(Uri uri, boolean leaf, IContentObserver observer, boolean observerWantsSelfNotifications, int flags, int targetUserHandle, ObserverCollector collector)1855 private void collectMyObserversLocked(Uri uri, boolean leaf, IContentObserver observer, 1856 boolean observerWantsSelfNotifications, int flags, 1857 int targetUserHandle, ObserverCollector collector) { 1858 int N = mObservers.size(); 1859 IBinder observerBinder = observer == null ? null : observer.asBinder(); 1860 for (int i = 0; i < N; i++) { 1861 ObserverEntry entry = mObservers.get(i); 1862 1863 // Don't notify the observer if it sent the notification and isn't interested 1864 // in self notifications 1865 boolean selfChange = (entry.observer.asBinder() == observerBinder); 1866 if (selfChange && !observerWantsSelfNotifications) { 1867 continue; 1868 } 1869 1870 // Does this observer match the target user? 1871 if (targetUserHandle == UserHandle.USER_ALL 1872 || entry.userHandle == UserHandle.USER_ALL 1873 || targetUserHandle == entry.userHandle) { 1874 // Make sure the observer is interested in the notification 1875 if (leaf) { 1876 // If we are at the leaf: we always report, unless the sender has asked 1877 // to skip observers that are notifying for descendants (since they will 1878 // be sending another more specific URI for them). 1879 if ((flags&ContentResolver.NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS) != 0 1880 && entry.notifyForDescendants) { 1881 if (DEBUG) Slog.d(TAG, "Skipping " + entry.observer 1882 + ": skip notify for descendants"); 1883 continue; 1884 } 1885 } else { 1886 // If we are not at the leaf: we report if the observer says it wants 1887 // to be notified for all descendants. 1888 if (!entry.notifyForDescendants) { 1889 if (DEBUG) Slog.d(TAG, "Skipping " + entry.observer 1890 + ": not monitor descendants"); 1891 continue; 1892 } 1893 } 1894 if (DEBUG) Slog.d(TAG, "Reporting to " + entry.observer + ": leaf=" + leaf 1895 + " flags=" + Integer.toHexString(flags) 1896 + " desc=" + entry.notifyForDescendants); 1897 collector.collect(entry.observer, entry.uid, selfChange, uri, flags, 1898 targetUserHandle); 1899 } 1900 } 1901 } 1902 1903 @VisibleForTesting collectObserversLocked(Uri uri, int index, IContentObserver observer, boolean observerWantsSelfNotifications, int flags, int targetUserHandle, ObserverCollector collector)1904 public void collectObserversLocked(Uri uri, int index, 1905 IContentObserver observer, boolean observerWantsSelfNotifications, int flags, 1906 int targetUserHandle, ObserverCollector collector) { 1907 collectObserversLocked(uri, countUriSegments(uri), index, observer, 1908 observerWantsSelfNotifications, flags, targetUserHandle, collector); 1909 } 1910 1911 /** 1912 * targetUserHandle is either a hard user handle or is USER_ALL 1913 */ collectObserversLocked(Uri uri, int segmentCount, int index, IContentObserver observer, boolean observerWantsSelfNotifications, int flags, int targetUserHandle, ObserverCollector collector)1914 public void collectObserversLocked(Uri uri, int segmentCount, int index, 1915 IContentObserver observer, boolean observerWantsSelfNotifications, int flags, 1916 int targetUserHandle, ObserverCollector collector) { 1917 String segment = null; 1918 if (index >= segmentCount) { 1919 // This is the leaf node, notify all observers 1920 if (DEBUG) Slog.d(TAG, "Collecting leaf observers @ #" + index + ", node " + mName); 1921 collectMyObserversLocked(uri, true, observer, observerWantsSelfNotifications, 1922 flags, targetUserHandle, collector); 1923 } else if (index < segmentCount){ 1924 segment = getUriSegment(uri, index); 1925 if (DEBUG) Slog.d(TAG, "Collecting non-leaf observers @ #" + index + " / " 1926 + segment); 1927 // Notify any observers at this level who are interested in descendants 1928 collectMyObserversLocked(uri, false, observer, observerWantsSelfNotifications, 1929 flags, targetUserHandle, collector); 1930 } 1931 1932 int N = mChildren.size(); 1933 for (int i = 0; i < N; i++) { 1934 ObserverNode node = mChildren.get(i); 1935 if (segment == null || node.mName.equals(segment)) { 1936 // We found the child, 1937 node.collectObserversLocked(uri, segmentCount, index + 1, observer, 1938 observerWantsSelfNotifications, flags, targetUserHandle, collector); 1939 if (segment != null) { 1940 break; 1941 } 1942 } 1943 } 1944 } 1945 } 1946 enforceShell(String method)1947 private void enforceShell(String method) { 1948 final int callingUid = Binder.getCallingUid(); 1949 if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID) { 1950 throw new SecurityException("Non-shell user attempted to call " + method); 1951 } 1952 } 1953 1954 @Override resetTodayStats()1955 public void resetTodayStats() { 1956 enforceShell("resetTodayStats"); 1957 1958 if (mSyncManager != null) { 1959 final long token = Binder.clearCallingIdentity(); 1960 try { 1961 mSyncManager.resetTodayStats(); 1962 } finally { 1963 Binder.restoreCallingIdentity(token); 1964 } 1965 } 1966 } 1967 1968 @Override onDbCorruption(String tag, String message, String stacktrace)1969 public void onDbCorruption(String tag, String message, String stacktrace) { 1970 Slog.e(tag, message); 1971 Slog.e(tag, "at " + stacktrace); 1972 1973 // TODO: Figure out a better way to report it. b/117886381 1974 Slog.wtf(tag, message); 1975 } 1976 1977 @Override onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)1978 public void onShellCommand(FileDescriptor in, FileDescriptor out, 1979 FileDescriptor err, String[] args, ShellCallback callback, 1980 ResultReceiver resultReceiver) { 1981 (new ContentShellCommand(this)).exec(this, in, out, err, args, callback, resultReceiver); 1982 } 1983 } 1984