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