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 android.Manifest; 20 import android.accounts.Account; 21 import android.annotation.Nullable; 22 import android.annotation.RequiresPermission; 23 import android.app.ActivityManager; 24 import android.app.ActivityManagerInternal; 25 import android.app.AppGlobals; 26 import android.app.AppOpsManager; 27 import android.app.job.JobInfo; 28 import android.content.BroadcastReceiver; 29 import android.content.ComponentName; 30 import android.content.ContentResolver; 31 import android.content.ContentResolver.SyncExemption; 32 import android.content.Context; 33 import android.content.IContentService; 34 import android.content.ISyncStatusObserver; 35 import android.content.Intent; 36 import android.content.IntentFilter; 37 import android.content.PeriodicSync; 38 import android.content.SyncAdapterType; 39 import android.content.SyncInfo; 40 import android.content.SyncRequest; 41 import android.content.SyncStatusInfo; 42 import android.content.pm.PackageManager; 43 import android.content.pm.PackageManagerInternal; 44 import android.content.pm.ProviderInfo; 45 import android.database.IContentObserver; 46 import android.database.sqlite.SQLiteException; 47 import android.net.Uri; 48 import android.os.Binder; 49 import android.os.Build; 50 import android.os.Bundle; 51 import android.os.FactoryTest; 52 import android.os.IBinder; 53 import android.os.Process; 54 import android.os.RemoteException; 55 import android.os.ResultReceiver; 56 import android.os.ShellCallback; 57 import android.os.UserHandle; 58 import android.text.TextUtils; 59 import android.util.ArrayMap; 60 import android.util.ArraySet; 61 import android.util.Log; 62 import android.util.Pair; 63 import android.util.Slog; 64 import android.util.SparseArray; 65 import android.util.SparseIntArray; 66 67 import com.android.internal.annotations.GuardedBy; 68 import com.android.internal.os.BinderDeathDispatcher; 69 import com.android.internal.util.ArrayUtils; 70 import com.android.internal.util.DumpUtils; 71 import com.android.internal.util.IndentingPrintWriter; 72 import com.android.server.LocalServices; 73 import com.android.server.SystemService; 74 75 import java.io.FileDescriptor; 76 import java.io.PrintWriter; 77 import java.util.ArrayList; 78 import java.util.Collections; 79 import java.util.Comparator; 80 import java.util.List; 81 82 /** 83 * {@hide} 84 */ 85 public final class ContentService extends IContentService.Stub { 86 static final String TAG = "ContentService"; 87 static final boolean DEBUG = false; 88 89 /** Do a WTF if a single observer is registered more than this times. */ 90 private static final int TOO_MANY_OBSERVERS_THRESHOLD = 1000; 91 92 public static class Lifecycle extends SystemService { 93 private ContentService mService; 94 95 public Lifecycle(Context context) { 96 super(context); 97 } 98 99 @Override 100 public void onStart() { 101 final boolean factoryTest = (FactoryTest 102 .getMode() == FactoryTest.FACTORY_TEST_LOW_LEVEL); 103 mService = new ContentService(getContext(), factoryTest); 104 publishBinderService(ContentResolver.CONTENT_SERVICE_NAME, mService); 105 } 106 107 @Override 108 public void onBootPhase(int phase) { 109 mService.onBootPhase(phase); 110 } 111 112 113 @Override 114 public void onStartUser(int userHandle) { 115 mService.onStartUser(userHandle); 116 } 117 118 @Override 119 public void onUnlockUser(int userHandle) { 120 mService.onUnlockUser(userHandle); 121 } 122 123 @Override 124 public void onStopUser(int userHandle) { 125 mService.onStopUser(userHandle); 126 } 127 128 @Override 129 public void onCleanupUser(int userHandle) { 130 synchronized (mService.mCache) { 131 mService.mCache.remove(userHandle); 132 } 133 } 134 } 135 136 private Context mContext; 137 private boolean mFactoryTest; 138 139 private final ObserverNode mRootNode = new ObserverNode(""); 140 141 private SyncManager mSyncManager = null; 142 private final Object mSyncManagerLock = new Object(); 143 144 private static final BinderDeathDispatcher<IContentObserver> sObserverDeathDispatcher = 145 new BinderDeathDispatcher<>(); 146 147 @GuardedBy("sObserverLeakDetectedUid") 148 private static final ArraySet<Integer> sObserverLeakDetectedUid = new ArraySet<>(0); 149 150 /** 151 * Map from userId to providerPackageName to [clientPackageName, uri] to 152 * value. This structure is carefully optimized to keep invalidation logic 153 * as cheap as possible. 154 */ 155 @GuardedBy("mCache") 156 private final SparseArray<ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>>> 157 mCache = new SparseArray<>(); 158 159 private BroadcastReceiver mCacheReceiver = new BroadcastReceiver() { 160 @Override 161 public void onReceive(Context context, Intent intent) { 162 synchronized (mCache) { 163 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) { 164 mCache.clear(); 165 } else { 166 final Uri data = intent.getData(); 167 if (data != null) { 168 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 169 UserHandle.USER_NULL); 170 final String packageName = data.getSchemeSpecificPart(); 171 invalidateCacheLocked(userId, packageName, null); 172 } 173 } 174 } 175 } 176 }; 177 178 private SyncManager getSyncManager() { 179 synchronized(mSyncManagerLock) { 180 try { 181 // Try to create the SyncManager, return null if it fails (which it shouldn't). 182 if (mSyncManager == null) mSyncManager = new SyncManager(mContext, mFactoryTest); 183 } catch (SQLiteException e) { 184 Log.e(TAG, "Can't create SyncManager", e); 185 } 186 return mSyncManager; 187 } 188 } 189 190 void onStartUser(int userHandle) { 191 if (mSyncManager != null) mSyncManager.onStartUser(userHandle); 192 } 193 194 void onUnlockUser(int userHandle) { 195 if (mSyncManager != null) mSyncManager.onUnlockUser(userHandle); 196 } 197 198 void onStopUser(int userHandle) { 199 if (mSyncManager != null) mSyncManager.onStopUser(userHandle); 200 } 201 202 @Override 203 protected synchronized void dump(FileDescriptor fd, PrintWriter pw_, String[] args) { 204 if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw_)) return; 205 final IndentingPrintWriter pw = new IndentingPrintWriter(pw_, " "); 206 207 final boolean dumpAll = ArrayUtils.contains(args, "-a"); 208 209 // This makes it so that future permission checks will be in the context of this 210 // process rather than the caller's process. We will restore this before returning. 211 final long identityToken = clearCallingIdentity(); 212 try { 213 if (mSyncManager == null) { 214 pw.println("SyncManager not available yet"); 215 } else { 216 mSyncManager.dump(fd, pw, dumpAll); 217 } 218 pw.println(); 219 pw.println("Observer tree:"); 220 synchronized (mRootNode) { 221 int[] counts = new int[2]; 222 final SparseIntArray pidCounts = new SparseIntArray(); 223 mRootNode.dumpLocked(fd, pw, args, "", " ", counts, pidCounts); 224 pw.println(); 225 ArrayList<Integer> sorted = new ArrayList<Integer>(); 226 for (int i=0; i<pidCounts.size(); i++) { 227 sorted.add(pidCounts.keyAt(i)); 228 } 229 Collections.sort(sorted, new Comparator<Integer>() { 230 @Override 231 public int compare(Integer lhs, Integer rhs) { 232 int lc = pidCounts.get(lhs); 233 int rc = pidCounts.get(rhs); 234 if (lc < rc) { 235 return 1; 236 } else if (lc > rc) { 237 return -1; 238 } 239 return 0; 240 } 241 242 }); 243 for (int i=0; i<sorted.size(); i++) { 244 int pid = sorted.get(i); 245 pw.print(" pid "); pw.print(pid); pw.print(": "); 246 pw.print(pidCounts.get(pid)); pw.println(" observers"); 247 } 248 pw.println(); 249 pw.print(" Total number of nodes: "); pw.println(counts[0]); 250 pw.print(" Total number of observers: "); pw.println(counts[1]); 251 252 sObserverDeathDispatcher.dump(pw, " "); 253 } 254 synchronized (sObserverLeakDetectedUid) { 255 pw.println(); 256 pw.print("Observer leaking UIDs: "); 257 pw.println(sObserverLeakDetectedUid.toString()); 258 } 259 260 synchronized (mCache) { 261 pw.println(); 262 pw.println("Cached content:"); 263 pw.increaseIndent(); 264 for (int i = 0; i < mCache.size(); i++) { 265 pw.println("User " + mCache.keyAt(i) + ":"); 266 pw.increaseIndent(); 267 pw.println(mCache.valueAt(i)); 268 pw.decreaseIndent(); 269 } 270 pw.decreaseIndent(); 271 } 272 } finally { 273 restoreCallingIdentity(identityToken); 274 } 275 } 276 277 /*package*/ ContentService(Context context, boolean factoryTest) { 278 mContext = context; 279 mFactoryTest = factoryTest; 280 281 // Let the package manager query for the sync adapters for a given authority 282 // as we grant default permissions to sync adapters for specific authorities. 283 PackageManagerInternal packageManagerInternal = LocalServices.getService( 284 PackageManagerInternal.class); 285 packageManagerInternal.setSyncAdapterPackagesprovider( 286 new PackageManagerInternal.SyncAdapterPackagesProvider() { 287 @Override 288 public String[] getPackages(String authority, int userId) { 289 return getSyncAdapterPackagesForAuthorityAsUser(authority, userId); 290 } 291 }); 292 293 final IntentFilter packageFilter = new IntentFilter(); 294 packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 295 packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 296 packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 297 packageFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED); 298 packageFilter.addDataScheme("package"); 299 mContext.registerReceiverAsUser(mCacheReceiver, UserHandle.ALL, 300 packageFilter, null, null); 301 302 final IntentFilter localeFilter = new IntentFilter(); 303 localeFilter.addAction(Intent.ACTION_LOCALE_CHANGED); 304 mContext.registerReceiverAsUser(mCacheReceiver, UserHandle.ALL, 305 localeFilter, null, null); 306 } 307 308 void onBootPhase(int phase) { 309 switch (phase) { 310 case SystemService.PHASE_ACTIVITY_MANAGER_READY: 311 getSyncManager(); 312 break; 313 } 314 if (mSyncManager != null) { 315 mSyncManager.onBootPhase(phase); 316 } 317 } 318 319 /** 320 * Register a content observer tied to a specific user's view of the provider. 321 * @param userHandle the user whose view of the provider is to be observed. May be 322 * the calling user without requiring any permission, otherwise the caller needs to 323 * hold the INTERACT_ACROSS_USERS_FULL permission or hold a read uri grant to the uri. 324 * Pseudousers USER_ALL and USER_CURRENT are properly handled; all other pseudousers 325 * are forbidden. 326 */ 327 @Override 328 public void registerContentObserver(Uri uri, boolean notifyForDescendants, 329 IContentObserver observer, int userHandle, int targetSdkVersion) { 330 if (observer == null || uri == null) { 331 throw new IllegalArgumentException("You must pass a valid uri and observer"); 332 } 333 334 final int uid = Binder.getCallingUid(); 335 final int pid = Binder.getCallingPid(); 336 337 userHandle = handleIncomingUser(uri, pid, uid, 338 Intent.FLAG_GRANT_READ_URI_PERMISSION, true, userHandle); 339 340 final String msg = LocalServices.getService(ActivityManagerInternal.class) 341 .checkContentProviderAccess(uri.getAuthority(), userHandle); 342 if (msg != null) { 343 if (targetSdkVersion >= Build.VERSION_CODES.O) { 344 throw new SecurityException(msg); 345 } else { 346 if (msg.startsWith("Failed to find provider")) { 347 // Sigh, we need to quietly let apps targeting older API 348 // levels notify on non-existent providers. 349 } else { 350 Log.w(TAG, "Ignoring content changes for " + uri + " from " + uid + ": " + msg); 351 return; 352 } 353 } 354 } 355 356 synchronized (mRootNode) { 357 mRootNode.addObserverLocked(uri, observer, notifyForDescendants, mRootNode, 358 uid, pid, userHandle); 359 if (false) Log.v(TAG, "Registered observer " + observer + " at " + uri + 360 " with notifyForDescendants " + notifyForDescendants); 361 } 362 } 363 364 public void registerContentObserver(Uri uri, boolean notifyForDescendants, 365 IContentObserver observer) { 366 registerContentObserver(uri, notifyForDescendants, observer, 367 UserHandle.getCallingUserId(), Build.VERSION_CODES.CUR_DEVELOPMENT); 368 } 369 370 @Override 371 public void unregisterContentObserver(IContentObserver observer) { 372 if (observer == null) { 373 throw new IllegalArgumentException("You must pass a valid observer"); 374 } 375 synchronized (mRootNode) { 376 mRootNode.removeObserverLocked(observer); 377 if (false) Log.v(TAG, "Unregistered observer " + observer); 378 } 379 } 380 381 /** 382 * Notify observers of a particular user's view of the provider. 383 * @param userHandle the user whose view of the provider is to be notified. May be 384 * the calling user without requiring any permission, otherwise the caller needs to 385 * hold the INTERACT_ACROSS_USERS_FULL permission or hold a write uri grant to the uri. 386 * Pseudousers USER_ALL and USER_CURRENT are properly interpreted; no other pseudousers are 387 * allowed. 388 */ 389 @Override 390 public void notifyChange(Uri uri, IContentObserver observer, 391 boolean observerWantsSelfNotifications, int flags, int userHandle, 392 int targetSdkVersion, String callingPackage) { 393 if (DEBUG) Slog.d(TAG, "Notifying update of " + uri + " for user " + userHandle 394 + " from observer " + observer + ", flags " + Integer.toHexString(flags)); 395 396 if (uri == null) { 397 throw new NullPointerException("Uri must not be null"); 398 } 399 400 final int callingUid = Binder.getCallingUid(); 401 final int callingPid = Binder.getCallingPid(); 402 final int callingUserHandle = UserHandle.getCallingUserId(); 403 404 userHandle = handleIncomingUser(uri, callingPid, callingUid, 405 Intent.FLAG_GRANT_WRITE_URI_PERMISSION, true, userHandle); 406 407 final String msg = LocalServices.getService(ActivityManagerInternal.class) 408 .checkContentProviderAccess(uri.getAuthority(), userHandle); 409 if (msg != null) { 410 if (targetSdkVersion >= Build.VERSION_CODES.O) { 411 throw new SecurityException(msg); 412 } else { 413 if (msg.startsWith("Failed to find provider")) { 414 // Sigh, we need to quietly let apps targeting older API 415 // levels notify on non-existent providers. 416 } else { 417 Log.w(TAG, "Ignoring notify for " + uri + " from " + callingUid + ": " + msg); 418 return; 419 } 420 } 421 } 422 423 // This makes it so that future permission checks will be in the context of this 424 // process rather than the caller's process. We will restore this before returning. 425 long identityToken = clearCallingIdentity(); 426 try { 427 ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>(); 428 synchronized (mRootNode) { 429 mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications, 430 flags, userHandle, calls); 431 } 432 final int numCalls = calls.size(); 433 for (int i=0; i<numCalls; i++) { 434 ObserverCall oc = calls.get(i); 435 try { 436 oc.mObserver.onChange(oc.mSelfChange, uri, userHandle); 437 if (DEBUG) Slog.d(TAG, "Notified " + oc.mObserver + " of " + "update at " 438 + uri); 439 } catch (RemoteException ex) { 440 synchronized (mRootNode) { 441 Log.w(TAG, "Found dead observer, removing"); 442 IBinder binder = oc.mObserver.asBinder(); 443 final ArrayList<ObserverNode.ObserverEntry> list 444 = oc.mNode.mObservers; 445 int numList = list.size(); 446 for (int j=0; j<numList; j++) { 447 ObserverNode.ObserverEntry oe = list.get(j); 448 if (oe.observer.asBinder() == binder) { 449 list.remove(j); 450 j--; 451 numList--; 452 } 453 } 454 } 455 } 456 } 457 if ((flags&ContentResolver.NOTIFY_SYNC_TO_NETWORK) != 0) { 458 SyncManager syncManager = getSyncManager(); 459 if (syncManager != null) { 460 syncManager.scheduleLocalSync(null /* all accounts */, callingUserHandle, 461 callingUid, 462 uri.getAuthority(), getSyncExemptionForCaller(callingUid), 463 callingUid, callingPid, callingPackage); 464 } 465 } 466 467 synchronized (mCache) { 468 final String providerPackageName = getProviderPackageName(uri); 469 invalidateCacheLocked(userHandle, providerPackageName, uri); 470 } 471 } finally { 472 restoreCallingIdentity(identityToken); 473 } 474 } 475 476 private int checkUriPermission(Uri uri, int pid, int uid, int modeFlags, int userHandle) { 477 try { 478 return ActivityManager.getService().checkUriPermission( 479 uri, pid, uid, modeFlags, userHandle, null); 480 } catch (RemoteException e) { 481 return PackageManager.PERMISSION_DENIED; 482 } 483 } 484 485 public void notifyChange(Uri uri, IContentObserver observer, 486 boolean observerWantsSelfNotifications, boolean syncToNetwork, 487 String callingPackage) { 488 notifyChange(uri, observer, observerWantsSelfNotifications, 489 syncToNetwork ? ContentResolver.NOTIFY_SYNC_TO_NETWORK : 0, 490 UserHandle.getCallingUserId(), Build.VERSION_CODES.CUR_DEVELOPMENT, callingPackage); 491 } 492 493 /** 494 * Hide this class since it is not part of api, 495 * but current unittest framework requires it to be public 496 * @hide 497 * 498 */ 499 public static final class ObserverCall { 500 final ObserverNode mNode; 501 final IContentObserver mObserver; 502 final boolean mSelfChange; 503 final int mObserverUserId; 504 505 ObserverCall(ObserverNode node, IContentObserver observer, boolean selfChange, int observerUserId) { 506 mNode = node; 507 mObserver = observer; 508 mSelfChange = selfChange; 509 mObserverUserId = observerUserId; 510 } 511 } 512 513 @Override 514 public void requestSync(Account account, String authority, Bundle extras, 515 String callingPackage) { 516 Bundle.setDefusable(extras, true); 517 ContentResolver.validateSyncExtrasBundle(extras); 518 int userId = UserHandle.getCallingUserId(); 519 final int callingUid = Binder.getCallingUid(); 520 final int callingPid = Binder.getCallingPid(); 521 522 validateExtras(callingUid, extras); 523 final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(callingUid, extras); 524 525 // This makes it so that future permission checks will be in the context of this 526 // process rather than the caller's process. We will restore this before returning. 527 long identityToken = clearCallingIdentity(); 528 try { 529 SyncManager syncManager = getSyncManager(); 530 if (syncManager != null) { 531 syncManager.scheduleSync(account, userId, callingUid, authority, extras, 532 SyncStorageEngine.AuthorityInfo.UNDEFINED, 533 syncExemption, callingUid, callingPid, callingPackage); 534 } 535 } finally { 536 restoreCallingIdentity(identityToken); 537 } 538 } 539 540 /** 541 * Request a sync with a generic {@link android.content.SyncRequest} object. This will be 542 * either: 543 * periodic OR one-off sync. 544 * and 545 * anonymous OR provider sync. 546 * Depending on the request, we enqueue to suit in the SyncManager. 547 * @param request The request object. Validation of this object is done by its builder. 548 */ 549 @Override 550 public void sync(SyncRequest request, String callingPackage) { 551 syncAsUser(request, UserHandle.getCallingUserId(), callingPackage); 552 } 553 554 private long clampPeriod(long period) { 555 long minPeriod = JobInfo.getMinPeriodMillis() / 1000; 556 if (period < minPeriod) { 557 Slog.w(TAG, "Requested poll frequency of " + period 558 + " seconds being rounded up to " + minPeriod + "s."); 559 period = minPeriod; 560 } 561 return period; 562 } 563 564 /** 565 * If the user id supplied is different to the calling user, the caller must hold the 566 * INTERACT_ACROSS_USERS_FULL permission. 567 */ 568 @Override 569 public void syncAsUser(SyncRequest request, int userId, String callingPackage) { 570 enforceCrossUserPermission(userId, "no permission to request sync as user: " + userId); 571 final int callingUid = Binder.getCallingUid(); 572 final int callingPid = Binder.getCallingPid(); 573 574 final Bundle extras = request.getBundle(); 575 576 validateExtras(callingUid, extras); 577 final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(callingUid, extras); 578 579 // This makes it so that future permission checks will be in the context of this 580 // process rather than the caller's process. We will restore this before returning. 581 long identityToken = clearCallingIdentity(); 582 try { 583 SyncManager syncManager = getSyncManager(); 584 if (syncManager == null) { 585 return; 586 } 587 long flextime = request.getSyncFlexTime(); 588 long runAtTime = request.getSyncRunTime(); 589 if (request.isPeriodic()) { 590 mContext.enforceCallingOrSelfPermission( 591 Manifest.permission.WRITE_SYNC_SETTINGS, 592 "no permission to write the sync settings"); 593 SyncStorageEngine.EndPoint info; 594 info = new SyncStorageEngine.EndPoint( 595 request.getAccount(), request.getProvider(), userId); 596 597 runAtTime = clampPeriod(runAtTime); 598 // Schedule periodic sync. 599 getSyncManager().updateOrAddPeriodicSync(info, runAtTime, 600 flextime, extras); 601 } else { 602 syncManager.scheduleSync( 603 request.getAccount(), userId, callingUid, request.getProvider(), extras, 604 SyncStorageEngine.AuthorityInfo.UNDEFINED, 605 syncExemption, callingUid, callingPid, callingPackage); 606 } 607 } finally { 608 restoreCallingIdentity(identityToken); 609 } 610 } 611 612 /** 613 * Clear all scheduled sync operations that match the uri and cancel the active sync 614 * if they match the authority and account, if they are present. 615 * 616 * @param account filter the pending and active syncs to cancel using this account, or null. 617 * @param authority filter the pending and active syncs to cancel using this authority, or 618 * null. 619 * @param cname cancel syncs running on this service, or null for provider/account. 620 */ 621 @Override 622 public void cancelSync(Account account, String authority, ComponentName cname) { 623 cancelSyncAsUser(account, authority, cname, UserHandle.getCallingUserId()); 624 } 625 626 /** 627 * Clear all scheduled sync operations that match the uri and cancel the active sync 628 * if they match the authority and account, if they are present. 629 * 630 * <p> If the user id supplied is different to the calling user, the caller must hold the 631 * INTERACT_ACROSS_USERS_FULL permission. 632 * 633 * @param account filter the pending and active syncs to cancel using this account, or null. 634 * @param authority filter the pending and active syncs to cancel using this authority, or 635 * null. 636 * @param userId the user id for which to cancel sync operations. 637 * @param cname cancel syncs running on this service, or null for provider/account. 638 */ 639 @Override 640 public void cancelSyncAsUser(Account account, String authority, ComponentName cname, 641 int userId) { 642 if (authority != null && authority.length() == 0) { 643 throw new IllegalArgumentException("Authority must be non-empty"); 644 } 645 enforceCrossUserPermission(userId, 646 "no permission to modify the sync settings for user " + userId); 647 // This makes it so that future permission checks will be in the context of this 648 // process rather than the caller's process. We will restore this before returning. 649 long identityToken = clearCallingIdentity(); 650 if (cname != null) { 651 Slog.e(TAG, "cname not null."); 652 return; 653 } 654 try { 655 SyncManager syncManager = getSyncManager(); 656 if (syncManager != null) { 657 SyncStorageEngine.EndPoint info; 658 info = new SyncStorageEngine.EndPoint(account, authority, userId); 659 syncManager.clearScheduledSyncOperations(info); 660 syncManager.cancelActiveSync(info, null /* all syncs for this adapter */, "API"); 661 } 662 } finally { 663 restoreCallingIdentity(identityToken); 664 } 665 } 666 667 @Override 668 public void cancelRequest(SyncRequest request) { 669 SyncManager syncManager = getSyncManager(); 670 if (syncManager == null) return; 671 int userId = UserHandle.getCallingUserId(); 672 final int callingUid = Binder.getCallingUid(); 673 674 if (request.isPeriodic()) { 675 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, 676 "no permission to write the sync settings"); 677 } 678 679 Bundle extras = new Bundle(request.getBundle()); 680 validateExtras(callingUid, extras); 681 682 long identityToken = clearCallingIdentity(); 683 try { 684 SyncStorageEngine.EndPoint info; 685 686 Account account = request.getAccount(); 687 String provider = request.getProvider(); 688 info = new SyncStorageEngine.EndPoint(account, provider, userId); 689 if (request.isPeriodic()) { 690 // Remove periodic sync. 691 getSyncManager().removePeriodicSync(info, extras, 692 "cancelRequest() by uid=" + callingUid); 693 } 694 // Cancel active syncs and clear pending syncs from the queue. 695 syncManager.cancelScheduledSyncOperation(info, extras); 696 syncManager.cancelActiveSync(info, extras, "API"); 697 } finally { 698 restoreCallingIdentity(identityToken); 699 } 700 } 701 702 /** 703 * Get information about the SyncAdapters that are known to the system. 704 * @return an array of SyncAdapters that have registered with the system 705 */ 706 @Override 707 public SyncAdapterType[] getSyncAdapterTypes() { 708 return getSyncAdapterTypesAsUser(UserHandle.getCallingUserId()); 709 } 710 711 /** 712 * Get information about the SyncAdapters that are known to the system for a particular user. 713 * 714 * <p> If the user id supplied is different to the calling user, the caller must hold the 715 * INTERACT_ACROSS_USERS_FULL permission. 716 * 717 * @return an array of SyncAdapters that have registered with the system 718 */ 719 @Override 720 public SyncAdapterType[] getSyncAdapterTypesAsUser(int userId) { 721 enforceCrossUserPermission(userId, 722 "no permission to read sync settings for user " + userId); 723 // This makes it so that future permission checks will be in the context of this 724 // process rather than the caller's process. We will restore this before returning. 725 final long identityToken = clearCallingIdentity(); 726 try { 727 SyncManager syncManager = getSyncManager(); 728 return syncManager.getSyncAdapterTypes(userId); 729 } finally { 730 restoreCallingIdentity(identityToken); 731 } 732 } 733 734 @Override 735 public String[] getSyncAdapterPackagesForAuthorityAsUser(String authority, int userId) { 736 enforceCrossUserPermission(userId, 737 "no permission to read sync settings for user " + userId); 738 // This makes it so that future permission checks will be in the context of this 739 // process rather than the caller's process. We will restore this before returning. 740 final long identityToken = clearCallingIdentity(); 741 try { 742 SyncManager syncManager = getSyncManager(); 743 return syncManager.getSyncAdapterPackagesForAuthorityAsUser(authority, userId); 744 } finally { 745 restoreCallingIdentity(identityToken); 746 } 747 } 748 749 @Override 750 public boolean getSyncAutomatically(Account account, String providerName) { 751 return getSyncAutomaticallyAsUser(account, providerName, UserHandle.getCallingUserId()); 752 } 753 754 /** 755 * If the user id supplied is different to the calling user, the caller must hold the 756 * INTERACT_ACROSS_USERS_FULL permission. 757 */ 758 @Override 759 public boolean getSyncAutomaticallyAsUser(Account account, String providerName, int userId) { 760 enforceCrossUserPermission(userId, 761 "no permission to read the sync settings for user " + userId); 762 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, 763 "no permission to read the sync settings"); 764 765 long identityToken = clearCallingIdentity(); 766 try { 767 SyncManager syncManager = getSyncManager(); 768 if (syncManager != null) { 769 return syncManager.getSyncStorageEngine() 770 .getSyncAutomatically(account, userId, providerName); 771 } 772 } finally { 773 restoreCallingIdentity(identityToken); 774 } 775 return false; 776 } 777 778 @Override 779 public void setSyncAutomatically(Account account, String providerName, boolean sync) { 780 setSyncAutomaticallyAsUser(account, providerName, sync, UserHandle.getCallingUserId()); 781 } 782 783 @Override 784 public void setSyncAutomaticallyAsUser(Account account, String providerName, boolean sync, 785 int userId) { 786 if (TextUtils.isEmpty(providerName)) { 787 throw new IllegalArgumentException("Authority must be non-empty"); 788 } 789 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, 790 "no permission to write the sync settings"); 791 enforceCrossUserPermission(userId, 792 "no permission to modify the sync settings for user " + userId); 793 final int callingUid = Binder.getCallingUid(); 794 final int callingPid = Binder.getCallingPid(); 795 final int syncExemptionFlag = getSyncExemptionForCaller(callingUid); 796 797 long identityToken = clearCallingIdentity(); 798 try { 799 SyncManager syncManager = getSyncManager(); 800 if (syncManager != null) { 801 syncManager.getSyncStorageEngine().setSyncAutomatically(account, userId, 802 providerName, sync, syncExemptionFlag, callingUid, callingPid); 803 } 804 } finally { 805 restoreCallingIdentity(identityToken); 806 } 807 } 808 809 /** Old API. Schedule periodic sync with default flexMillis time. */ 810 @Override 811 public void addPeriodicSync(Account account, String authority, Bundle extras, 812 long pollFrequency) { 813 Bundle.setDefusable(extras, true); 814 if (account == null) { 815 throw new IllegalArgumentException("Account must not be null"); 816 } 817 if (TextUtils.isEmpty(authority)) { 818 throw new IllegalArgumentException("Authority must not be empty."); 819 } 820 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, 821 "no permission to write the sync settings"); 822 823 validateExtras(Binder.getCallingUid(), extras); 824 825 int userId = UserHandle.getCallingUserId(); 826 827 pollFrequency = clampPeriod(pollFrequency); 828 long defaultFlex = SyncStorageEngine.calculateDefaultFlexTime(pollFrequency); 829 830 long identityToken = clearCallingIdentity(); 831 try { 832 SyncStorageEngine.EndPoint info = 833 new SyncStorageEngine.EndPoint(account, authority, userId); 834 getSyncManager().updateOrAddPeriodicSync(info, pollFrequency, 835 defaultFlex, extras); 836 } finally { 837 restoreCallingIdentity(identityToken); 838 } 839 } 840 841 @Override 842 public void removePeriodicSync(Account account, String authority, Bundle extras) { 843 Bundle.setDefusable(extras, true); 844 if (account == null) { 845 throw new IllegalArgumentException("Account must not be null"); 846 } 847 if (TextUtils.isEmpty(authority)) { 848 throw new IllegalArgumentException("Authority must not be empty"); 849 } 850 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, 851 "no permission to write the sync settings"); 852 853 validateExtras(Binder.getCallingUid(), extras); 854 855 final int callingUid = Binder.getCallingUid(); 856 857 int userId = UserHandle.getCallingUserId(); 858 long identityToken = clearCallingIdentity(); 859 try { 860 getSyncManager() 861 .removePeriodicSync( 862 new SyncStorageEngine.EndPoint(account, authority, userId), 863 extras, "removePeriodicSync() by uid=" + callingUid); 864 } finally { 865 restoreCallingIdentity(identityToken); 866 } 867 } 868 869 @Override 870 public List<PeriodicSync> getPeriodicSyncs(Account account, String providerName, 871 ComponentName cname) { 872 if (account == null) { 873 throw new IllegalArgumentException("Account must not be null"); 874 } 875 if (TextUtils.isEmpty(providerName)) { 876 throw new IllegalArgumentException("Authority must not be empty"); 877 } 878 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, 879 "no permission to read the sync settings"); 880 881 int userId = UserHandle.getCallingUserId(); 882 long identityToken = clearCallingIdentity(); 883 try { 884 return getSyncManager().getPeriodicSyncs( 885 new SyncStorageEngine.EndPoint(account, providerName, userId)); 886 } finally { 887 restoreCallingIdentity(identityToken); 888 } 889 } 890 891 @Override 892 public int getIsSyncable(Account account, String providerName) { 893 return getIsSyncableAsUser(account, providerName, UserHandle.getCallingUserId()); 894 } 895 896 /** 897 * If the user id supplied is different to the calling user, the caller must hold the 898 * INTERACT_ACROSS_USERS_FULL permission. 899 */ 900 @Override 901 public int getIsSyncableAsUser(Account account, String providerName, int userId) { 902 enforceCrossUserPermission(userId, 903 "no permission to read the sync settings for user " + userId); 904 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, 905 "no permission to read the sync settings"); 906 907 long identityToken = clearCallingIdentity(); 908 try { 909 SyncManager syncManager = getSyncManager(); 910 if (syncManager != null) { 911 return syncManager.computeSyncable( 912 account, userId, providerName, false); 913 } 914 } finally { 915 restoreCallingIdentity(identityToken); 916 } 917 return -1; 918 } 919 920 @Override 921 public void setIsSyncable(Account account, String providerName, int syncable) { 922 setIsSyncableAsUser(account, providerName, syncable, UserHandle.getCallingUserId()); 923 } 924 925 /** 926 * @hide 927 */ 928 @Override 929 public void setIsSyncableAsUser(Account account, String providerName, int syncable, 930 int userId) { 931 if (TextUtils.isEmpty(providerName)) { 932 throw new IllegalArgumentException("Authority must not be empty"); 933 } 934 enforceCrossUserPermission(userId, 935 "no permission to set the sync settings for user " + userId); 936 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, 937 "no permission to write the sync settings"); 938 939 syncable = normalizeSyncable(syncable); 940 final int callingUid = Binder.getCallingUid(); 941 final int callingPid = Binder.getCallingPid(); 942 943 long identityToken = clearCallingIdentity(); 944 try { 945 SyncManager syncManager = getSyncManager(); 946 if (syncManager != null) { 947 syncManager.getSyncStorageEngine().setIsSyncable( 948 account, userId, providerName, syncable, callingUid, callingPid); 949 } 950 } finally { 951 restoreCallingIdentity(identityToken); 952 } 953 } 954 955 @Override 956 public boolean getMasterSyncAutomatically() { 957 return getMasterSyncAutomaticallyAsUser(UserHandle.getCallingUserId()); 958 } 959 960 /** 961 * If the user id supplied is different to the calling user, the caller must hold the 962 * INTERACT_ACROSS_USERS_FULL permission. 963 */ 964 @Override 965 public boolean getMasterSyncAutomaticallyAsUser(int userId) { 966 enforceCrossUserPermission(userId, 967 "no permission to read the sync settings for user " + userId); 968 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, 969 "no permission to read the sync settings"); 970 971 long identityToken = clearCallingIdentity(); 972 try { 973 SyncManager syncManager = getSyncManager(); 974 if (syncManager != null) { 975 return syncManager.getSyncStorageEngine().getMasterSyncAutomatically(userId); 976 } 977 } finally { 978 restoreCallingIdentity(identityToken); 979 } 980 return false; 981 } 982 983 @Override 984 public void setMasterSyncAutomatically(boolean flag) { 985 setMasterSyncAutomaticallyAsUser(flag, UserHandle.getCallingUserId()); 986 } 987 988 @Override 989 public void setMasterSyncAutomaticallyAsUser(boolean flag, int userId) { 990 enforceCrossUserPermission(userId, 991 "no permission to set the sync status for user " + userId); 992 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, 993 "no permission to write the sync settings"); 994 995 final int callingUid = Binder.getCallingUid(); 996 final int callingPid = Binder.getCallingPid(); 997 998 long identityToken = clearCallingIdentity(); 999 try { 1000 SyncManager syncManager = getSyncManager(); 1001 if (syncManager != null) { 1002 syncManager.getSyncStorageEngine().setMasterSyncAutomatically(flag, userId, 1003 getSyncExemptionForCaller(callingUid), callingUid, callingPid); 1004 } 1005 } finally { 1006 restoreCallingIdentity(identityToken); 1007 } 1008 } 1009 1010 @Override 1011 public boolean isSyncActive(Account account, String authority, ComponentName cname) { 1012 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS, 1013 "no permission to read the sync stats"); 1014 int userId = UserHandle.getCallingUserId(); 1015 long identityToken = clearCallingIdentity(); 1016 try { 1017 SyncManager syncManager = getSyncManager(); 1018 if (syncManager == null) { 1019 return false; 1020 } 1021 return syncManager.getSyncStorageEngine().isSyncActive( 1022 new SyncStorageEngine.EndPoint(account, authority, userId)); 1023 } finally { 1024 restoreCallingIdentity(identityToken); 1025 } 1026 } 1027 1028 @Override 1029 public List<SyncInfo> getCurrentSyncs() { 1030 return getCurrentSyncsAsUser(UserHandle.getCallingUserId()); 1031 } 1032 1033 /** 1034 * If the user id supplied is different to the calling user, the caller must hold the 1035 * INTERACT_ACROSS_USERS_FULL permission. 1036 */ 1037 @Override 1038 public List<SyncInfo> getCurrentSyncsAsUser(int userId) { 1039 enforceCrossUserPermission(userId, 1040 "no permission to read the sync settings for user " + userId); 1041 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS, 1042 "no permission to read the sync stats"); 1043 1044 final boolean canAccessAccounts = 1045 mContext.checkCallingOrSelfPermission(Manifest.permission.GET_ACCOUNTS) 1046 == PackageManager.PERMISSION_GRANTED; 1047 long identityToken = clearCallingIdentity(); 1048 try { 1049 return getSyncManager().getSyncStorageEngine() 1050 .getCurrentSyncsCopy(userId, canAccessAccounts); 1051 } finally { 1052 restoreCallingIdentity(identityToken); 1053 } 1054 } 1055 1056 @Override 1057 public SyncStatusInfo getSyncStatus(Account account, String authority, ComponentName cname) { 1058 return getSyncStatusAsUser(account, authority, cname, UserHandle.getCallingUserId()); 1059 } 1060 1061 /** 1062 * If the user id supplied is different to the calling user, the caller must hold the 1063 * INTERACT_ACROSS_USERS_FULL permission. 1064 */ 1065 @Override 1066 public SyncStatusInfo getSyncStatusAsUser(Account account, String authority, 1067 ComponentName cname, int userId) { 1068 if (TextUtils.isEmpty(authority)) { 1069 throw new IllegalArgumentException("Authority must not be empty"); 1070 } 1071 1072 enforceCrossUserPermission(userId, 1073 "no permission to read the sync stats for user " + userId); 1074 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS, 1075 "no permission to read the sync stats"); 1076 1077 long identityToken = clearCallingIdentity(); 1078 try { 1079 SyncManager syncManager = getSyncManager(); 1080 if (syncManager == null) { 1081 return null; 1082 } 1083 SyncStorageEngine.EndPoint info; 1084 if (!(account == null || authority == null)) { 1085 info = new SyncStorageEngine.EndPoint(account, authority, userId); 1086 } else { 1087 throw new IllegalArgumentException("Must call sync status with valid authority"); 1088 } 1089 return syncManager.getSyncStorageEngine().getStatusByAuthority(info); 1090 } finally { 1091 restoreCallingIdentity(identityToken); 1092 } 1093 } 1094 1095 @Override 1096 public boolean isSyncPending(Account account, String authority, ComponentName cname) { 1097 return isSyncPendingAsUser(account, authority, cname, UserHandle.getCallingUserId()); 1098 } 1099 1100 @Override 1101 public boolean isSyncPendingAsUser(Account account, String authority, ComponentName cname, 1102 int userId) { 1103 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS, 1104 "no permission to read the sync stats"); 1105 enforceCrossUserPermission(userId, 1106 "no permission to retrieve the sync settings for user " + userId); 1107 long identityToken = clearCallingIdentity(); 1108 SyncManager syncManager = getSyncManager(); 1109 if (syncManager == null) return false; 1110 1111 try { 1112 SyncStorageEngine.EndPoint info; 1113 if (!(account == null || authority == null)) { 1114 info = new SyncStorageEngine.EndPoint(account, authority, userId); 1115 } else { 1116 throw new IllegalArgumentException("Invalid authority specified"); 1117 } 1118 return syncManager.getSyncStorageEngine().isSyncPending(info); 1119 } finally { 1120 restoreCallingIdentity(identityToken); 1121 } 1122 } 1123 1124 @Override 1125 public void addStatusChangeListener(int mask, ISyncStatusObserver callback) { 1126 final int callingUid = Binder.getCallingUid(); 1127 long identityToken = clearCallingIdentity(); 1128 try { 1129 SyncManager syncManager = getSyncManager(); 1130 if (syncManager != null && callback != null) { 1131 syncManager.getSyncStorageEngine().addStatusChangeListener( 1132 mask, UserHandle.getUserId(callingUid), callback); 1133 } 1134 } finally { 1135 restoreCallingIdentity(identityToken); 1136 } 1137 } 1138 1139 @Override 1140 public void removeStatusChangeListener(ISyncStatusObserver callback) { 1141 long identityToken = clearCallingIdentity(); 1142 try { 1143 SyncManager syncManager = getSyncManager(); 1144 if (syncManager != null && callback != null) { 1145 syncManager.getSyncStorageEngine().removeStatusChangeListener(callback); 1146 } 1147 } finally { 1148 restoreCallingIdentity(identityToken); 1149 } 1150 } 1151 1152 private @Nullable String getProviderPackageName(Uri uri) { 1153 final ProviderInfo pi = mContext.getPackageManager() 1154 .resolveContentProvider(uri.getAuthority(), 0); 1155 return (pi != null) ? pi.packageName : null; 1156 } 1157 1158 @GuardedBy("mCache") 1159 private ArrayMap<Pair<String, Uri>, Bundle> findOrCreateCacheLocked(int userId, 1160 String providerPackageName) { 1161 ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>> userCache = mCache.get(userId); 1162 if (userCache == null) { 1163 userCache = new ArrayMap<>(); 1164 mCache.put(userId, userCache); 1165 } 1166 ArrayMap<Pair<String, Uri>, Bundle> packageCache = userCache.get(providerPackageName); 1167 if (packageCache == null) { 1168 packageCache = new ArrayMap<>(); 1169 userCache.put(providerPackageName, packageCache); 1170 } 1171 return packageCache; 1172 } 1173 1174 @GuardedBy("mCache") 1175 private void invalidateCacheLocked(int userId, String providerPackageName, Uri uri) { 1176 ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>> userCache = mCache.get(userId); 1177 if (userCache == null) return; 1178 1179 ArrayMap<Pair<String, Uri>, Bundle> packageCache = userCache.get(providerPackageName); 1180 if (packageCache == null) return; 1181 1182 if (uri != null) { 1183 for (int i = 0; i < packageCache.size();) { 1184 final Pair<String, Uri> key = packageCache.keyAt(i); 1185 if (key.second != null && key.second.toString().startsWith(uri.toString())) { 1186 if (DEBUG) Slog.d(TAG, "Invalidating cache for key " + key); 1187 packageCache.removeAt(i); 1188 } else { 1189 i++; 1190 } 1191 } 1192 } else { 1193 if (DEBUG) Slog.d(TAG, "Invalidating cache for package " + providerPackageName); 1194 packageCache.clear(); 1195 } 1196 } 1197 1198 @Override 1199 @RequiresPermission(android.Manifest.permission.CACHE_CONTENT) 1200 public void putCache(String packageName, Uri key, Bundle value, int userId) { 1201 Bundle.setDefusable(value, true); 1202 enforceCrossUserPermission(userId, TAG); 1203 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CACHE_CONTENT, TAG); 1204 mContext.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(), 1205 packageName); 1206 1207 final String providerPackageName = getProviderPackageName(key); 1208 final Pair<String, Uri> fullKey = Pair.create(packageName, key); 1209 1210 synchronized (mCache) { 1211 final ArrayMap<Pair<String, Uri>, Bundle> cache = findOrCreateCacheLocked(userId, 1212 providerPackageName); 1213 if (value != null) { 1214 cache.put(fullKey, value); 1215 } else { 1216 cache.remove(fullKey); 1217 } 1218 } 1219 } 1220 1221 @Override 1222 @RequiresPermission(android.Manifest.permission.CACHE_CONTENT) 1223 public Bundle getCache(String packageName, Uri key, int userId) { 1224 enforceCrossUserPermission(userId, TAG); 1225 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CACHE_CONTENT, TAG); 1226 mContext.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(), 1227 packageName); 1228 1229 final String providerPackageName = getProviderPackageName(key); 1230 final Pair<String, Uri> fullKey = Pair.create(packageName, key); 1231 1232 synchronized (mCache) { 1233 final ArrayMap<Pair<String, Uri>, Bundle> cache = findOrCreateCacheLocked(userId, 1234 providerPackageName); 1235 return cache.get(fullKey); 1236 } 1237 } 1238 1239 private int handleIncomingUser(Uri uri, int pid, int uid, int modeFlags, boolean allowNonFull, 1240 int userId) { 1241 if (userId == UserHandle.USER_CURRENT) { 1242 userId = ActivityManager.getCurrentUser(); 1243 } 1244 1245 if (userId == UserHandle.USER_ALL) { 1246 mContext.enforceCallingOrSelfPermission( 1247 Manifest.permission.INTERACT_ACROSS_USERS_FULL, "No access to " + uri); 1248 } else if (userId < 0) { 1249 throw new IllegalArgumentException("Invalid user: " + userId); 1250 } else if (userId != UserHandle.getCallingUserId()) { 1251 if (checkUriPermission(uri, pid, uid, modeFlags, 1252 userId) != PackageManager.PERMISSION_GRANTED) { 1253 boolean allow = false; 1254 if (mContext.checkCallingOrSelfPermission( 1255 Manifest.permission.INTERACT_ACROSS_USERS_FULL) 1256 == PackageManager.PERMISSION_GRANTED) { 1257 allow = true; 1258 } else if (allowNonFull && mContext.checkCallingOrSelfPermission( 1259 Manifest.permission.INTERACT_ACROSS_USERS) 1260 == PackageManager.PERMISSION_GRANTED) { 1261 allow = true; 1262 } 1263 if (!allow) { 1264 final String permissions = allowNonFull 1265 ? (Manifest.permission.INTERACT_ACROSS_USERS_FULL + " or " + 1266 Manifest.permission.INTERACT_ACROSS_USERS) 1267 : Manifest.permission.INTERACT_ACROSS_USERS_FULL; 1268 throw new SecurityException("No access to " + uri + ": neither user " + uid 1269 + " nor current process has " + permissions); 1270 } 1271 } 1272 } 1273 1274 return userId; 1275 } 1276 1277 /** 1278 * Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS_FULL 1279 * permission, if the userHandle is not for the caller. 1280 * 1281 * @param userHandle the user handle of the user we want to act on behalf of. 1282 * @param message the message to log on security exception. 1283 */ 1284 private void enforceCrossUserPermission(int userHandle, String message) { 1285 final int callingUser = UserHandle.getCallingUserId(); 1286 if (callingUser != userHandle) { 1287 mContext.enforceCallingOrSelfPermission( 1288 Manifest.permission.INTERACT_ACROSS_USERS_FULL, message); 1289 } 1290 } 1291 1292 private static int normalizeSyncable(int syncable) { 1293 if (syncable > 0) { 1294 return SyncStorageEngine.AuthorityInfo.SYNCABLE; 1295 } else if (syncable == 0) { 1296 return SyncStorageEngine.AuthorityInfo.NOT_SYNCABLE; 1297 } 1298 return SyncStorageEngine.AuthorityInfo.UNDEFINED; 1299 } 1300 1301 private void validateExtras(int callingUid, Bundle extras) { 1302 if (extras.containsKey(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG)) { 1303 switch (callingUid) { 1304 case Process.ROOT_UID: 1305 case Process.SHELL_UID: 1306 case Process.SYSTEM_UID: 1307 break; // Okay 1308 default: 1309 final String msg = "Invalid extras specified."; 1310 Log.w(TAG, msg + " requestsync -f/-F needs to run on 'adb shell'"); 1311 throw new SecurityException(msg); 1312 } 1313 } 1314 } 1315 1316 @SyncExemption 1317 private int getSyncExemptionForCaller(int callingUid) { 1318 return getSyncExemptionAndCleanUpExtrasForCaller(callingUid, null); 1319 } 1320 1321 @SyncExemption 1322 private int getSyncExemptionAndCleanUpExtrasForCaller(int callingUid, Bundle extras) { 1323 if (extras != null) { 1324 final int exemption = 1325 extras.getInt(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG, -1); 1326 1327 // Need to remove the virtual extra. 1328 extras.remove(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG); 1329 if (exemption != -1) { 1330 return exemption; 1331 } 1332 } 1333 final ActivityManagerInternal ami = 1334 LocalServices.getService(ActivityManagerInternal.class); 1335 if (ami == null) { 1336 return ContentResolver.SYNC_EXEMPTION_NONE; 1337 } 1338 final int procState = ami.getUidProcessState(callingUid); 1339 final boolean isUidActive = ami.isUidActive(callingUid); 1340 1341 // Providers bound by a TOP app will get PROCESS_STATE_BOUND_TOP, so include those as well 1342 if (procState <= ActivityManager.PROCESS_STATE_TOP 1343 || procState == ActivityManager.PROCESS_STATE_BOUND_TOP) { 1344 return ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP; 1345 } 1346 if (procState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND || isUidActive) { 1347 return ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET; 1348 } 1349 return ContentResolver.SYNC_EXEMPTION_NONE; 1350 } 1351 1352 /** 1353 * Hide this class since it is not part of api, 1354 * but current unittest framework requires it to be public 1355 * @hide 1356 */ 1357 public static final class ObserverNode { 1358 private class ObserverEntry implements IBinder.DeathRecipient { 1359 public final IContentObserver observer; 1360 public final int uid; 1361 public final int pid; 1362 public final boolean notifyForDescendants; 1363 private final int userHandle; 1364 private final Object observersLock; 1365 1366 public ObserverEntry(IContentObserver o, boolean n, Object observersLock, 1367 int _uid, int _pid, int _userHandle, Uri uri) { 1368 this.observersLock = observersLock; 1369 observer = o; 1370 uid = _uid; 1371 pid = _pid; 1372 userHandle = _userHandle; 1373 notifyForDescendants = n; 1374 1375 final int entries = sObserverDeathDispatcher.linkToDeath(observer, this); 1376 if (entries == -1) { 1377 binderDied(); 1378 } else if (entries == TOO_MANY_OBSERVERS_THRESHOLD) { 1379 boolean alreadyDetected; 1380 1381 synchronized (sObserverLeakDetectedUid) { 1382 alreadyDetected = sObserverLeakDetectedUid.contains(uid); 1383 if (!alreadyDetected) { 1384 sObserverLeakDetectedUid.add(uid); 1385 } 1386 } 1387 if (!alreadyDetected) { 1388 String caller = null; 1389 try { 1390 caller = ArrayUtils.firstOrNull(AppGlobals.getPackageManager() 1391 .getPackagesForUid(uid)); 1392 } catch (RemoteException ignore) { 1393 } 1394 Slog.wtf(TAG, "Observer registered too many times. Leak? cpid=" + pid 1395 + " cuid=" + uid 1396 + " cpkg=" + caller 1397 + " url=" + uri); 1398 } 1399 } 1400 1401 } 1402 1403 @Override 1404 public void binderDied() { 1405 synchronized (observersLock) { 1406 removeObserverLocked(observer); 1407 } 1408 } 1409 1410 public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args, 1411 String name, String prefix, SparseIntArray pidCounts) { 1412 pidCounts.put(pid, pidCounts.get(pid)+1); 1413 pw.print(prefix); pw.print(name); pw.print(": pid="); 1414 pw.print(pid); pw.print(" uid="); 1415 pw.print(uid); pw.print(" user="); 1416 pw.print(userHandle); pw.print(" target="); 1417 pw.println(Integer.toHexString(System.identityHashCode( 1418 observer != null ? observer.asBinder() : null))); 1419 } 1420 } 1421 1422 public static final int INSERT_TYPE = 0; 1423 public static final int UPDATE_TYPE = 1; 1424 public static final int DELETE_TYPE = 2; 1425 1426 private String mName; 1427 private ArrayList<ObserverNode> mChildren = new ArrayList<ObserverNode>(); 1428 private ArrayList<ObserverEntry> mObservers = new ArrayList<ObserverEntry>(); 1429 1430 public ObserverNode(String name) { 1431 mName = name; 1432 } 1433 1434 public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args, 1435 String name, String prefix, int[] counts, SparseIntArray pidCounts) { 1436 String innerName = null; 1437 if (mObservers.size() > 0) { 1438 if ("".equals(name)) { 1439 innerName = mName; 1440 } else { 1441 innerName = name + "/" + mName; 1442 } 1443 for (int i=0; i<mObservers.size(); i++) { 1444 counts[1]++; 1445 mObservers.get(i).dumpLocked(fd, pw, args, innerName, prefix, 1446 pidCounts); 1447 } 1448 } 1449 if (mChildren.size() > 0) { 1450 if (innerName == null) { 1451 if ("".equals(name)) { 1452 innerName = mName; 1453 } else { 1454 innerName = name + "/" + mName; 1455 } 1456 } 1457 for (int i=0; i<mChildren.size(); i++) { 1458 counts[0]++; 1459 mChildren.get(i).dumpLocked(fd, pw, args, innerName, prefix, 1460 counts, pidCounts); 1461 } 1462 } 1463 } 1464 1465 private String getUriSegment(Uri uri, int index) { 1466 if (uri != null) { 1467 if (index == 0) { 1468 return uri.getAuthority(); 1469 } else { 1470 return uri.getPathSegments().get(index - 1); 1471 } 1472 } else { 1473 return null; 1474 } 1475 } 1476 1477 private int countUriSegments(Uri uri) { 1478 if (uri == null) { 1479 return 0; 1480 } 1481 return uri.getPathSegments().size() + 1; 1482 } 1483 1484 // Invariant: userHandle is either a hard user number or is USER_ALL 1485 public void addObserverLocked(Uri uri, IContentObserver observer, 1486 boolean notifyForDescendants, Object observersLock, 1487 int uid, int pid, int userHandle) { 1488 addObserverLocked(uri, 0, observer, notifyForDescendants, observersLock, 1489 uid, pid, userHandle); 1490 } 1491 1492 private void addObserverLocked(Uri uri, int index, IContentObserver observer, 1493 boolean notifyForDescendants, Object observersLock, 1494 int uid, int pid, int userHandle) { 1495 // If this is the leaf node add the observer 1496 if (index == countUriSegments(uri)) { 1497 mObservers.add(new ObserverEntry(observer, notifyForDescendants, observersLock, 1498 uid, pid, userHandle, uri)); 1499 return; 1500 } 1501 1502 // Look to see if the proper child already exists 1503 String segment = getUriSegment(uri, index); 1504 if (segment == null) { 1505 throw new IllegalArgumentException("Invalid Uri (" + uri + ") used for observer"); 1506 } 1507 int N = mChildren.size(); 1508 for (int i = 0; i < N; i++) { 1509 ObserverNode node = mChildren.get(i); 1510 if (node.mName.equals(segment)) { 1511 node.addObserverLocked(uri, index + 1, observer, notifyForDescendants, 1512 observersLock, uid, pid, userHandle); 1513 return; 1514 } 1515 } 1516 1517 // No child found, create one 1518 ObserverNode node = new ObserverNode(segment); 1519 mChildren.add(node); 1520 node.addObserverLocked(uri, index + 1, observer, notifyForDescendants, 1521 observersLock, uid, pid, userHandle); 1522 } 1523 1524 public boolean removeObserverLocked(IContentObserver observer) { 1525 int size = mChildren.size(); 1526 for (int i = 0; i < size; i++) { 1527 boolean empty = mChildren.get(i).removeObserverLocked(observer); 1528 if (empty) { 1529 mChildren.remove(i); 1530 i--; 1531 size--; 1532 } 1533 } 1534 1535 IBinder observerBinder = observer.asBinder(); 1536 size = mObservers.size(); 1537 for (int i = 0; i < size; i++) { 1538 ObserverEntry entry = mObservers.get(i); 1539 if (entry.observer.asBinder() == observerBinder) { 1540 mObservers.remove(i); 1541 // We no longer need to listen for death notifications. Remove it. 1542 sObserverDeathDispatcher.unlinkToDeath(observer, entry); 1543 break; 1544 } 1545 } 1546 1547 if (mChildren.size() == 0 && mObservers.size() == 0) { 1548 return true; 1549 } 1550 return false; 1551 } 1552 1553 private void collectMyObserversLocked(boolean leaf, IContentObserver observer, 1554 boolean observerWantsSelfNotifications, int flags, 1555 int targetUserHandle, ArrayList<ObserverCall> calls) { 1556 int N = mObservers.size(); 1557 IBinder observerBinder = observer == null ? null : observer.asBinder(); 1558 for (int i = 0; i < N; i++) { 1559 ObserverEntry entry = mObservers.get(i); 1560 1561 // Don't notify the observer if it sent the notification and isn't interested 1562 // in self notifications 1563 boolean selfChange = (entry.observer.asBinder() == observerBinder); 1564 if (selfChange && !observerWantsSelfNotifications) { 1565 continue; 1566 } 1567 1568 // Does this observer match the target user? 1569 if (targetUserHandle == UserHandle.USER_ALL 1570 || entry.userHandle == UserHandle.USER_ALL 1571 || targetUserHandle == entry.userHandle) { 1572 // Make sure the observer is interested in the notification 1573 if (leaf) { 1574 // If we are at the leaf: we always report, unless the sender has asked 1575 // to skip observers that are notifying for descendants (since they will 1576 // be sending another more specific URI for them). 1577 if ((flags&ContentResolver.NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS) != 0 1578 && entry.notifyForDescendants) { 1579 if (DEBUG) Slog.d(TAG, "Skipping " + entry.observer 1580 + ": skip notify for descendants"); 1581 continue; 1582 } 1583 } else { 1584 // If we are not at the leaf: we report if the observer says it wants 1585 // to be notified for all descendants. 1586 if (!entry.notifyForDescendants) { 1587 if (DEBUG) Slog.d(TAG, "Skipping " + entry.observer 1588 + ": not monitor descendants"); 1589 continue; 1590 } 1591 } 1592 if (DEBUG) Slog.d(TAG, "Reporting to " + entry.observer + ": leaf=" + leaf 1593 + " flags=" + Integer.toHexString(flags) 1594 + " desc=" + entry.notifyForDescendants); 1595 calls.add(new ObserverCall(this, entry.observer, selfChange, 1596 UserHandle.getUserId(entry.uid))); 1597 } 1598 } 1599 } 1600 1601 /** 1602 * targetUserHandle is either a hard user handle or is USER_ALL 1603 */ 1604 public void collectObserversLocked(Uri uri, int index, IContentObserver observer, 1605 boolean observerWantsSelfNotifications, int flags, 1606 int targetUserHandle, ArrayList<ObserverCall> calls) { 1607 String segment = null; 1608 int segmentCount = countUriSegments(uri); 1609 if (index >= segmentCount) { 1610 // This is the leaf node, notify all observers 1611 if (DEBUG) Slog.d(TAG, "Collecting leaf observers @ #" + index + ", node " + mName); 1612 collectMyObserversLocked(true, observer, observerWantsSelfNotifications, 1613 flags, targetUserHandle, calls); 1614 } else if (index < segmentCount){ 1615 segment = getUriSegment(uri, index); 1616 if (DEBUG) Slog.d(TAG, "Collecting non-leaf observers @ #" + index + " / " 1617 + segment); 1618 // Notify any observers at this level who are interested in descendants 1619 collectMyObserversLocked(false, observer, observerWantsSelfNotifications, 1620 flags, targetUserHandle, calls); 1621 } 1622 1623 int N = mChildren.size(); 1624 for (int i = 0; i < N; i++) { 1625 ObserverNode node = mChildren.get(i); 1626 if (segment == null || node.mName.equals(segment)) { 1627 // We found the child, 1628 node.collectObserversLocked(uri, index + 1, observer, 1629 observerWantsSelfNotifications, flags, targetUserHandle, calls); 1630 if (segment != null) { 1631 break; 1632 } 1633 } 1634 } 1635 } 1636 } 1637 1638 private void enforceShell(String method) { 1639 final int callingUid = Binder.getCallingUid(); 1640 if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID) { 1641 throw new SecurityException("Non-shell user attempted to call " + method); 1642 } 1643 } 1644 1645 @Override 1646 public void resetTodayStats() { 1647 enforceShell("resetTodayStats"); 1648 1649 if (mSyncManager != null) { 1650 final long token = Binder.clearCallingIdentity(); 1651 try { 1652 mSyncManager.resetTodayStats(); 1653 } finally { 1654 Binder.restoreCallingIdentity(token); 1655 } 1656 } 1657 } 1658 1659 @Override 1660 public void onDbCorruption(String tag, String message, String stacktrace) { 1661 Slog.e(tag, message); 1662 Slog.e(tag, "at " + stacktrace); 1663 1664 // TODO: Figure out a better way to report it. b/117886381 1665 Slog.wtf(tag, message); 1666 } 1667 1668 @Override 1669 public void onShellCommand(FileDescriptor in, FileDescriptor out, 1670 FileDescriptor err, String[] args, ShellCallback callback, 1671 ResultReceiver resultReceiver) { 1672 (new ContentShellCommand(this)).exec(this, in, out, err, args, callback, resultReceiver); 1673 } 1674 } 1675