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