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