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 oc.mObserver.onChange(oc.mSelfChange, uri, userHandle); 398 if (DEBUG) Slog.d(TAG, "Notified " + oc.mObserver + " of " + "update at " 399 + uri); 400 } catch (RemoteException ex) { 401 synchronized (mRootNode) { 402 Log.w(TAG, "Found dead observer, removing"); 403 IBinder binder = oc.mObserver.asBinder(); 404 final ArrayList<ObserverNode.ObserverEntry> list 405 = oc.mNode.mObservers; 406 int numList = list.size(); 407 for (int j=0; j<numList; j++) { 408 ObserverNode.ObserverEntry oe = list.get(j); 409 if (oe.observer.asBinder() == binder) { 410 list.remove(j); 411 j--; 412 numList--; 413 } 414 } 415 } 416 } 417 } 418 if ((flags&ContentResolver.NOTIFY_SYNC_TO_NETWORK) != 0) { 419 SyncManager syncManager = getSyncManager(); 420 if (syncManager != null) { 421 syncManager.scheduleLocalSync(null /* all accounts */, callingUserHandle, uid, 422 uri.getAuthority()); 423 } 424 } 425 426 synchronized (mCache) { 427 final String providerPackageName = getProviderPackageName(uri); 428 invalidateCacheLocked(userHandle, providerPackageName, uri); 429 } 430 } finally { 431 restoreCallingIdentity(identityToken); 432 } 433 } 434 435 private int checkUriPermission(Uri uri, int pid, int uid, int modeFlags, int userHandle) { 436 try { 437 return ActivityManagerNative.getDefault().checkUriPermission( 438 uri, pid, uid, modeFlags, userHandle, null); 439 } catch (RemoteException e) { 440 return PackageManager.PERMISSION_DENIED; 441 } 442 } 443 444 public void notifyChange(Uri uri, IContentObserver observer, 445 boolean observerWantsSelfNotifications, boolean syncToNetwork) { 446 notifyChange(uri, observer, observerWantsSelfNotifications, 447 syncToNetwork ? ContentResolver.NOTIFY_SYNC_TO_NETWORK : 0, 448 UserHandle.getCallingUserId()); 449 } 450 451 /** 452 * Hide this class since it is not part of api, 453 * but current unittest framework requires it to be public 454 * @hide 455 * 456 */ 457 public static final class ObserverCall { 458 final ObserverNode mNode; 459 final IContentObserver mObserver; 460 final boolean mSelfChange; 461 final int mObserverUserId; 462 463 ObserverCall(ObserverNode node, IContentObserver observer, boolean selfChange, int observerUserId) { 464 mNode = node; 465 mObserver = observer; 466 mSelfChange = selfChange; 467 mObserverUserId = observerUserId; 468 } 469 } 470 471 @Override 472 public void requestSync(Account account, String authority, Bundle extras) { 473 Bundle.setDefusable(extras, true); 474 ContentResolver.validateSyncExtrasBundle(extras); 475 int userId = UserHandle.getCallingUserId(); 476 int uId = Binder.getCallingUid(); 477 478 // This makes it so that future permission checks will be in the context of this 479 // process rather than the caller's process. We will restore this before returning. 480 long identityToken = clearCallingIdentity(); 481 try { 482 SyncManager syncManager = getSyncManager(); 483 if (syncManager != null) { 484 syncManager.scheduleSync(account, userId, uId, authority, extras, 485 SyncStorageEngine.AuthorityInfo.UNDEFINED); 486 } 487 } finally { 488 restoreCallingIdentity(identityToken); 489 } 490 } 491 492 /** 493 * Request a sync with a generic {@link android.content.SyncRequest} object. This will be 494 * either: 495 * periodic OR one-off sync. 496 * and 497 * anonymous OR provider sync. 498 * Depending on the request, we enqueue to suit in the SyncManager. 499 * @param request The request object. Validation of this object is done by its builder. 500 */ 501 @Override 502 public void sync(SyncRequest request) { 503 syncAsUser(request, UserHandle.getCallingUserId()); 504 } 505 506 private long clampPeriod(long period) { 507 long minPeriod = JobInfo.getMinPeriodMillis() / 1000; 508 if (period < minPeriod) { 509 Slog.w(TAG, "Requested poll frequency of " + period 510 + " seconds being rounded up to " + minPeriod + "s."); 511 period = minPeriod; 512 } 513 return period; 514 } 515 516 /** 517 * If the user id supplied is different to the calling user, the caller must hold the 518 * INTERACT_ACROSS_USERS_FULL permission. 519 */ 520 @Override 521 public void syncAsUser(SyncRequest request, int userId) { 522 enforceCrossUserPermission(userId, "no permission to request sync as user: " + userId); 523 int callerUid = Binder.getCallingUid(); 524 // This makes it so that future permission checks will be in the context of this 525 // process rather than the caller's process. We will restore this before returning. 526 long identityToken = clearCallingIdentity(); 527 try { 528 SyncManager syncManager = getSyncManager(); 529 if (syncManager == null) { 530 return; 531 } 532 533 Bundle extras = request.getBundle(); 534 long flextime = request.getSyncFlexTime(); 535 long runAtTime = request.getSyncRunTime(); 536 if (request.isPeriodic()) { 537 mContext.enforceCallingOrSelfPermission( 538 Manifest.permission.WRITE_SYNC_SETTINGS, 539 "no permission to write the sync settings"); 540 SyncStorageEngine.EndPoint info; 541 info = new SyncStorageEngine.EndPoint( 542 request.getAccount(), request.getProvider(), userId); 543 544 runAtTime = clampPeriod(runAtTime); 545 // Schedule periodic sync. 546 getSyncManager().updateOrAddPeriodicSync(info, runAtTime, 547 flextime, extras); 548 } else { 549 syncManager.scheduleSync( 550 request.getAccount(), userId, callerUid, request.getProvider(), extras, 551 SyncStorageEngine.AuthorityInfo.UNDEFINED); 552 } 553 } finally { 554 restoreCallingIdentity(identityToken); 555 } 556 } 557 558 /** 559 * Clear all scheduled sync operations that match the uri and cancel the active sync 560 * if they match the authority and account, if they are present. 561 * 562 * @param account filter the pending and active syncs to cancel using this account, or null. 563 * @param authority filter the pending and active syncs to cancel using this authority, or 564 * null. 565 * @param cname cancel syncs running on this service, or null for provider/account. 566 */ 567 @Override 568 public void cancelSync(Account account, String authority, ComponentName cname) { 569 cancelSyncAsUser(account, authority, cname, UserHandle.getCallingUserId()); 570 } 571 572 /** 573 * Clear all scheduled sync operations that match the uri and cancel the active sync 574 * if they match the authority and account, if they are present. 575 * 576 * <p> If the user id supplied is different to the calling user, the caller must hold the 577 * INTERACT_ACROSS_USERS_FULL permission. 578 * 579 * @param account filter the pending and active syncs to cancel using this account, or null. 580 * @param authority filter the pending and active syncs to cancel using this authority, or 581 * null. 582 * @param userId the user id for which to cancel sync operations. 583 * @param cname cancel syncs running on this service, or null for provider/account. 584 */ 585 @Override 586 public void cancelSyncAsUser(Account account, String authority, ComponentName cname, 587 int userId) { 588 if (authority != null && authority.length() == 0) { 589 throw new IllegalArgumentException("Authority must be non-empty"); 590 } 591 enforceCrossUserPermission(userId, 592 "no permission to modify the sync settings for user " + userId); 593 // This makes it so that future permission checks will be in the context of this 594 // process rather than the caller's process. We will restore this before returning. 595 long identityToken = clearCallingIdentity(); 596 if (cname != null) { 597 Slog.e(TAG, "cname not null."); 598 return; 599 } 600 try { 601 SyncManager syncManager = getSyncManager(); 602 if (syncManager != null) { 603 SyncStorageEngine.EndPoint info; 604 info = new SyncStorageEngine.EndPoint(account, authority, userId); 605 syncManager.clearScheduledSyncOperations(info); 606 syncManager.cancelActiveSync(info, null /* all syncs for this adapter */); 607 } 608 } finally { 609 restoreCallingIdentity(identityToken); 610 } 611 } 612 613 @Override 614 public void cancelRequest(SyncRequest request) { 615 SyncManager syncManager = getSyncManager(); 616 if (syncManager == null) return; 617 int userId = UserHandle.getCallingUserId(); 618 619 long identityToken = clearCallingIdentity(); 620 try { 621 SyncStorageEngine.EndPoint info; 622 Bundle extras = new Bundle(request.getBundle()); 623 Account account = request.getAccount(); 624 String provider = request.getProvider(); 625 info = new SyncStorageEngine.EndPoint(account, provider, userId); 626 if (request.isPeriodic()) { 627 // Remove periodic sync. 628 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, 629 "no permission to write the sync settings"); 630 getSyncManager().removePeriodicSync(info, extras); 631 } 632 // Cancel active syncs and clear pending syncs from the queue. 633 syncManager.cancelScheduledSyncOperation(info, extras); 634 syncManager.cancelActiveSync(info, extras); 635 } finally { 636 restoreCallingIdentity(identityToken); 637 } 638 } 639 640 /** 641 * Get information about the SyncAdapters that are known to the system. 642 * @return an array of SyncAdapters that have registered with the system 643 */ 644 @Override 645 public SyncAdapterType[] getSyncAdapterTypes() { 646 return getSyncAdapterTypesAsUser(UserHandle.getCallingUserId()); 647 } 648 649 /** 650 * Get information about the SyncAdapters that are known to the system for a particular user. 651 * 652 * <p> If the user id supplied is different to the calling user, the caller must hold the 653 * INTERACT_ACROSS_USERS_FULL permission. 654 * 655 * @return an array of SyncAdapters that have registered with the system 656 */ 657 @Override 658 public SyncAdapterType[] getSyncAdapterTypesAsUser(int userId) { 659 enforceCrossUserPermission(userId, 660 "no permission to read sync settings for user " + userId); 661 // This makes it so that future permission checks will be in the context of this 662 // process rather than the caller's process. We will restore this before returning. 663 final long identityToken = clearCallingIdentity(); 664 try { 665 SyncManager syncManager = getSyncManager(); 666 return syncManager.getSyncAdapterTypes(userId); 667 } finally { 668 restoreCallingIdentity(identityToken); 669 } 670 } 671 672 @Override 673 public String[] getSyncAdapterPackagesForAuthorityAsUser(String authority, int userId) { 674 enforceCrossUserPermission(userId, 675 "no permission to read sync settings for user " + userId); 676 // This makes it so that future permission checks will be in the context of this 677 // process rather than the caller's process. We will restore this before returning. 678 final long identityToken = clearCallingIdentity(); 679 try { 680 SyncManager syncManager = getSyncManager(); 681 return syncManager.getSyncAdapterPackagesForAuthorityAsUser(authority, userId); 682 } finally { 683 restoreCallingIdentity(identityToken); 684 } 685 } 686 687 @Override 688 public boolean getSyncAutomatically(Account account, String providerName) { 689 return getSyncAutomaticallyAsUser(account, providerName, UserHandle.getCallingUserId()); 690 } 691 692 /** 693 * If the user id supplied is different to the calling user, the caller must hold the 694 * INTERACT_ACROSS_USERS_FULL permission. 695 */ 696 @Override 697 public boolean getSyncAutomaticallyAsUser(Account account, String providerName, int userId) { 698 enforceCrossUserPermission(userId, 699 "no permission to read the sync settings for user " + userId); 700 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, 701 "no permission to read the sync settings"); 702 703 long identityToken = clearCallingIdentity(); 704 try { 705 SyncManager syncManager = getSyncManager(); 706 if (syncManager != null) { 707 return syncManager.getSyncStorageEngine() 708 .getSyncAutomatically(account, userId, providerName); 709 } 710 } finally { 711 restoreCallingIdentity(identityToken); 712 } 713 return false; 714 } 715 716 @Override 717 public void setSyncAutomatically(Account account, String providerName, boolean sync) { 718 setSyncAutomaticallyAsUser(account, providerName, sync, UserHandle.getCallingUserId()); 719 } 720 721 @Override 722 public void setSyncAutomaticallyAsUser(Account account, String providerName, boolean sync, 723 int userId) { 724 if (TextUtils.isEmpty(providerName)) { 725 throw new IllegalArgumentException("Authority must be non-empty"); 726 } 727 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, 728 "no permission to write the sync settings"); 729 enforceCrossUserPermission(userId, 730 "no permission to modify the sync settings for user " + userId); 731 732 long identityToken = clearCallingIdentity(); 733 try { 734 SyncManager syncManager = getSyncManager(); 735 if (syncManager != null) { 736 syncManager.getSyncStorageEngine().setSyncAutomatically(account, userId, 737 providerName, sync); 738 } 739 } finally { 740 restoreCallingIdentity(identityToken); 741 } 742 } 743 744 /** Old API. Schedule periodic sync with default flexMillis time. */ 745 @Override 746 public void addPeriodicSync(Account account, String authority, Bundle extras, 747 long pollFrequency) { 748 Bundle.setDefusable(extras, true); 749 if (account == null) { 750 throw new IllegalArgumentException("Account must not be null"); 751 } 752 if (TextUtils.isEmpty(authority)) { 753 throw new IllegalArgumentException("Authority must not be empty."); 754 } 755 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, 756 "no permission to write the sync settings"); 757 758 int userId = UserHandle.getCallingUserId(); 759 760 pollFrequency = clampPeriod(pollFrequency); 761 long defaultFlex = SyncStorageEngine.calculateDefaultFlexTime(pollFrequency); 762 763 long identityToken = clearCallingIdentity(); 764 try { 765 SyncStorageEngine.EndPoint info = 766 new SyncStorageEngine.EndPoint(account, authority, userId); 767 getSyncManager().updateOrAddPeriodicSync(info, pollFrequency, 768 defaultFlex, extras); 769 } finally { 770 restoreCallingIdentity(identityToken); 771 } 772 } 773 774 @Override 775 public void removePeriodicSync(Account account, String authority, Bundle extras) { 776 Bundle.setDefusable(extras, true); 777 if (account == null) { 778 throw new IllegalArgumentException("Account must not be null"); 779 } 780 if (TextUtils.isEmpty(authority)) { 781 throw new IllegalArgumentException("Authority must not be empty"); 782 } 783 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, 784 "no permission to write the sync settings"); 785 786 int userId = UserHandle.getCallingUserId(); 787 long identityToken = clearCallingIdentity(); 788 try { 789 getSyncManager() 790 .removePeriodicSync( 791 new SyncStorageEngine.EndPoint(account, authority, userId), 792 extras); 793 } finally { 794 restoreCallingIdentity(identityToken); 795 } 796 } 797 798 @Override 799 public List<PeriodicSync> getPeriodicSyncs(Account account, String providerName, 800 ComponentName cname) { 801 if (account == null) { 802 throw new IllegalArgumentException("Account must not be null"); 803 } 804 if (TextUtils.isEmpty(providerName)) { 805 throw new IllegalArgumentException("Authority must not be empty"); 806 } 807 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, 808 "no permission to read the sync settings"); 809 810 int userId = UserHandle.getCallingUserId(); 811 long identityToken = clearCallingIdentity(); 812 try { 813 return getSyncManager().getPeriodicSyncs( 814 new SyncStorageEngine.EndPoint(account, providerName, userId)); 815 } finally { 816 restoreCallingIdentity(identityToken); 817 } 818 } 819 820 @Override 821 public int getIsSyncable(Account account, String providerName) { 822 return getIsSyncableAsUser(account, providerName, UserHandle.getCallingUserId()); 823 } 824 825 /** 826 * If the user id supplied is different to the calling user, the caller must hold the 827 * INTERACT_ACROSS_USERS_FULL permission. 828 */ 829 @Override 830 public int getIsSyncableAsUser(Account account, String providerName, int userId) { 831 enforceCrossUserPermission(userId, 832 "no permission to read the sync settings for user " + userId); 833 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, 834 "no permission to read the sync settings"); 835 836 long identityToken = clearCallingIdentity(); 837 try { 838 SyncManager syncManager = getSyncManager(); 839 if (syncManager != null) { 840 return syncManager.computeSyncable( 841 account, userId, providerName, false); 842 } 843 } finally { 844 restoreCallingIdentity(identityToken); 845 } 846 return -1; 847 } 848 849 @Override 850 public void setIsSyncable(Account account, String providerName, int syncable) { 851 if (TextUtils.isEmpty(providerName)) { 852 throw new IllegalArgumentException("Authority must not be empty"); 853 } 854 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, 855 "no permission to write the sync settings"); 856 857 syncable = normalizeSyncable(syncable); 858 859 int userId = UserHandle.getCallingUserId(); 860 long identityToken = clearCallingIdentity(); 861 try { 862 SyncManager syncManager = getSyncManager(); 863 if (syncManager != null) { 864 syncManager.getSyncStorageEngine().setIsSyncable( 865 account, userId, providerName, syncable); 866 } 867 } finally { 868 restoreCallingIdentity(identityToken); 869 } 870 } 871 872 @Override 873 public boolean getMasterSyncAutomatically() { 874 return getMasterSyncAutomaticallyAsUser(UserHandle.getCallingUserId()); 875 } 876 877 /** 878 * If the user id supplied is different to the calling user, the caller must hold the 879 * INTERACT_ACROSS_USERS_FULL permission. 880 */ 881 @Override 882 public boolean getMasterSyncAutomaticallyAsUser(int userId) { 883 enforceCrossUserPermission(userId, 884 "no permission to read the sync settings for user " + userId); 885 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, 886 "no permission to read the sync settings"); 887 888 long identityToken = clearCallingIdentity(); 889 try { 890 SyncManager syncManager = getSyncManager(); 891 if (syncManager != null) { 892 return syncManager.getSyncStorageEngine().getMasterSyncAutomatically(userId); 893 } 894 } finally { 895 restoreCallingIdentity(identityToken); 896 } 897 return false; 898 } 899 900 @Override 901 public void setMasterSyncAutomatically(boolean flag) { 902 setMasterSyncAutomaticallyAsUser(flag, UserHandle.getCallingUserId()); 903 } 904 905 @Override 906 public void setMasterSyncAutomaticallyAsUser(boolean flag, int userId) { 907 enforceCrossUserPermission(userId, 908 "no permission to set the sync status for user " + userId); 909 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, 910 "no permission to write the sync settings"); 911 912 long identityToken = clearCallingIdentity(); 913 try { 914 SyncManager syncManager = getSyncManager(); 915 if (syncManager != null) { 916 syncManager.getSyncStorageEngine().setMasterSyncAutomatically(flag, userId); 917 } 918 } finally { 919 restoreCallingIdentity(identityToken); 920 } 921 } 922 923 @Override 924 public boolean isSyncActive(Account account, String authority, ComponentName cname) { 925 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS, 926 "no permission to read the sync stats"); 927 int userId = UserHandle.getCallingUserId(); 928 long identityToken = clearCallingIdentity(); 929 try { 930 SyncManager syncManager = getSyncManager(); 931 if (syncManager == null) { 932 return false; 933 } 934 return syncManager.getSyncStorageEngine().isSyncActive( 935 new SyncStorageEngine.EndPoint(account, authority, userId)); 936 } finally { 937 restoreCallingIdentity(identityToken); 938 } 939 } 940 941 @Override 942 public List<SyncInfo> getCurrentSyncs() { 943 return getCurrentSyncsAsUser(UserHandle.getCallingUserId()); 944 } 945 946 /** 947 * If the user id supplied is different to the calling user, the caller must hold the 948 * INTERACT_ACROSS_USERS_FULL permission. 949 */ 950 @Override 951 public List<SyncInfo> getCurrentSyncsAsUser(int userId) { 952 enforceCrossUserPermission(userId, 953 "no permission to read the sync settings for user " + userId); 954 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS, 955 "no permission to read the sync stats"); 956 957 final boolean canAccessAccounts = 958 mContext.checkCallingOrSelfPermission(Manifest.permission.GET_ACCOUNTS) 959 == PackageManager.PERMISSION_GRANTED; 960 long identityToken = clearCallingIdentity(); 961 try { 962 return getSyncManager().getSyncStorageEngine() 963 .getCurrentSyncsCopy(userId, canAccessAccounts); 964 } finally { 965 restoreCallingIdentity(identityToken); 966 } 967 } 968 969 @Override 970 public SyncStatusInfo getSyncStatus(Account account, String authority, ComponentName cname) { 971 return getSyncStatusAsUser(account, authority, cname, UserHandle.getCallingUserId()); 972 } 973 974 /** 975 * If the user id supplied is different to the calling user, the caller must hold the 976 * INTERACT_ACROSS_USERS_FULL permission. 977 */ 978 @Override 979 public SyncStatusInfo getSyncStatusAsUser(Account account, String authority, 980 ComponentName cname, int userId) { 981 if (TextUtils.isEmpty(authority)) { 982 throw new IllegalArgumentException("Authority must not be empty"); 983 } 984 985 enforceCrossUserPermission(userId, 986 "no permission to read the sync stats for user " + userId); 987 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS, 988 "no permission to read the sync stats"); 989 990 long identityToken = clearCallingIdentity(); 991 try { 992 SyncManager syncManager = getSyncManager(); 993 if (syncManager == null) { 994 return null; 995 } 996 SyncStorageEngine.EndPoint info; 997 if (!(account == null || authority == null)) { 998 info = new SyncStorageEngine.EndPoint(account, authority, userId); 999 } else { 1000 throw new IllegalArgumentException("Must call sync status with valid authority"); 1001 } 1002 return syncManager.getSyncStorageEngine().getStatusByAuthority(info); 1003 } finally { 1004 restoreCallingIdentity(identityToken); 1005 } 1006 } 1007 1008 @Override 1009 public boolean isSyncPending(Account account, String authority, ComponentName cname) { 1010 return isSyncPendingAsUser(account, authority, cname, UserHandle.getCallingUserId()); 1011 } 1012 1013 @Override 1014 public boolean isSyncPendingAsUser(Account account, String authority, ComponentName cname, 1015 int userId) { 1016 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS, 1017 "no permission to read the sync stats"); 1018 enforceCrossUserPermission(userId, 1019 "no permission to retrieve the sync settings for user " + userId); 1020 long identityToken = clearCallingIdentity(); 1021 SyncManager syncManager = getSyncManager(); 1022 if (syncManager == null) return false; 1023 1024 try { 1025 SyncStorageEngine.EndPoint info; 1026 if (!(account == null || authority == null)) { 1027 info = new SyncStorageEngine.EndPoint(account, authority, userId); 1028 } else { 1029 throw new IllegalArgumentException("Invalid authority specified"); 1030 } 1031 return syncManager.getSyncStorageEngine().isSyncPending(info); 1032 } finally { 1033 restoreCallingIdentity(identityToken); 1034 } 1035 } 1036 1037 @Override 1038 public void addStatusChangeListener(int mask, ISyncStatusObserver callback) { 1039 long identityToken = clearCallingIdentity(); 1040 try { 1041 SyncManager syncManager = getSyncManager(); 1042 if (syncManager != null && callback != null) { 1043 syncManager.getSyncStorageEngine().addStatusChangeListener(mask, callback); 1044 } 1045 } finally { 1046 restoreCallingIdentity(identityToken); 1047 } 1048 } 1049 1050 @Override 1051 public void removeStatusChangeListener(ISyncStatusObserver callback) { 1052 long identityToken = clearCallingIdentity(); 1053 try { 1054 SyncManager syncManager = getSyncManager(); 1055 if (syncManager != null && callback != null) { 1056 syncManager.getSyncStorageEngine().removeStatusChangeListener(callback); 1057 } 1058 } finally { 1059 restoreCallingIdentity(identityToken); 1060 } 1061 } 1062 1063 private @Nullable String getProviderPackageName(Uri uri) { 1064 final ProviderInfo pi = mContext.getPackageManager() 1065 .resolveContentProvider(uri.getAuthority(), 0); 1066 return (pi != null) ? pi.packageName : null; 1067 } 1068 1069 private ArrayMap<Pair<String, Uri>, Bundle> findOrCreateCacheLocked(int userId, 1070 String providerPackageName) { 1071 ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>> userCache = mCache.get(userId); 1072 if (userCache == null) { 1073 userCache = new ArrayMap<>(); 1074 mCache.put(userId, userCache); 1075 } 1076 ArrayMap<Pair<String, Uri>, Bundle> packageCache = userCache.get(providerPackageName); 1077 if (packageCache == null) { 1078 packageCache = new ArrayMap<>(); 1079 userCache.put(providerPackageName, packageCache); 1080 } 1081 return packageCache; 1082 } 1083 1084 private void invalidateCacheLocked(int userId, String providerPackageName, Uri uri) { 1085 ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>> userCache = mCache.get(userId); 1086 if (userCache == null) return; 1087 1088 ArrayMap<Pair<String, Uri>, Bundle> packageCache = userCache.get(providerPackageName); 1089 if (packageCache == null) return; 1090 1091 if (uri != null) { 1092 for (int i = 0; i < packageCache.size();) { 1093 final Pair<String, Uri> key = packageCache.keyAt(i); 1094 if (key.second != null && key.second.toString().startsWith(uri.toString())) { 1095 if (DEBUG) Slog.d(TAG, "Invalidating cache for key " + key); 1096 packageCache.removeAt(i); 1097 } else { 1098 i++; 1099 } 1100 } 1101 } else { 1102 if (DEBUG) Slog.d(TAG, "Invalidating cache for package " + providerPackageName); 1103 packageCache.clear(); 1104 } 1105 } 1106 1107 @Override 1108 public void putCache(String packageName, Uri key, Bundle value, int userId) { 1109 Bundle.setDefusable(value, true); 1110 enforceCrossUserPermission(userId, TAG); 1111 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CACHE_CONTENT, TAG); 1112 mContext.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(), 1113 packageName); 1114 1115 final String providerPackageName = getProviderPackageName(key); 1116 final Pair<String, Uri> fullKey = Pair.create(packageName, key); 1117 1118 synchronized (mCache) { 1119 final ArrayMap<Pair<String, Uri>, Bundle> cache = findOrCreateCacheLocked(userId, 1120 providerPackageName); 1121 if (value != null) { 1122 cache.put(fullKey, value); 1123 } else { 1124 cache.remove(fullKey); 1125 } 1126 } 1127 } 1128 1129 @Override 1130 public Bundle getCache(String packageName, Uri key, int userId) { 1131 enforceCrossUserPermission(userId, TAG); 1132 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CACHE_CONTENT, TAG); 1133 mContext.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(), 1134 packageName); 1135 1136 final String providerPackageName = getProviderPackageName(key); 1137 final Pair<String, Uri> fullKey = Pair.create(packageName, key); 1138 1139 synchronized (mCache) { 1140 final ArrayMap<Pair<String, Uri>, Bundle> cache = findOrCreateCacheLocked(userId, 1141 providerPackageName); 1142 return cache.get(fullKey); 1143 } 1144 } 1145 1146 /** 1147 * Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS_FULL 1148 * permission, if the userHandle is not for the caller. 1149 * 1150 * @param userHandle the user handle of the user we want to act on behalf of. 1151 * @param message the message to log on security exception. 1152 */ 1153 private void enforceCrossUserPermission(int userHandle, String message) { 1154 final int callingUser = UserHandle.getCallingUserId(); 1155 if (callingUser != userHandle) { 1156 mContext.enforceCallingOrSelfPermission( 1157 Manifest.permission.INTERACT_ACROSS_USERS_FULL, message); 1158 } 1159 } 1160 1161 private static int normalizeSyncable(int syncable) { 1162 if (syncable > 0) { 1163 return SyncStorageEngine.AuthorityInfo.SYNCABLE; 1164 } else if (syncable == 0) { 1165 return SyncStorageEngine.AuthorityInfo.NOT_SYNCABLE; 1166 } 1167 return SyncStorageEngine.AuthorityInfo.UNDEFINED; 1168 } 1169 1170 /** 1171 * Hide this class since it is not part of api, 1172 * but current unittest framework requires it to be public 1173 * @hide 1174 */ 1175 public static final class ObserverNode { 1176 private class ObserverEntry implements IBinder.DeathRecipient { 1177 public final IContentObserver observer; 1178 public final int uid; 1179 public final int pid; 1180 public final boolean notifyForDescendants; 1181 private final int userHandle; 1182 private final Object observersLock; 1183 1184 public ObserverEntry(IContentObserver o, boolean n, Object observersLock, 1185 int _uid, int _pid, int _userHandle) { 1186 this.observersLock = observersLock; 1187 observer = o; 1188 uid = _uid; 1189 pid = _pid; 1190 userHandle = _userHandle; 1191 notifyForDescendants = n; 1192 try { 1193 observer.asBinder().linkToDeath(this, 0); 1194 } catch (RemoteException e) { 1195 binderDied(); 1196 } 1197 } 1198 1199 @Override 1200 public void binderDied() { 1201 synchronized (observersLock) { 1202 removeObserverLocked(observer); 1203 } 1204 } 1205 1206 public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args, 1207 String name, String prefix, SparseIntArray pidCounts) { 1208 pidCounts.put(pid, pidCounts.get(pid)+1); 1209 pw.print(prefix); pw.print(name); pw.print(": pid="); 1210 pw.print(pid); pw.print(" uid="); 1211 pw.print(uid); pw.print(" user="); 1212 pw.print(userHandle); pw.print(" target="); 1213 pw.println(Integer.toHexString(System.identityHashCode( 1214 observer != null ? observer.asBinder() : null))); 1215 } 1216 } 1217 1218 public static final int INSERT_TYPE = 0; 1219 public static final int UPDATE_TYPE = 1; 1220 public static final int DELETE_TYPE = 2; 1221 1222 private String mName; 1223 private ArrayList<ObserverNode> mChildren = new ArrayList<ObserverNode>(); 1224 private ArrayList<ObserverEntry> mObservers = new ArrayList<ObserverEntry>(); 1225 1226 public ObserverNode(String name) { 1227 mName = name; 1228 } 1229 1230 public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args, 1231 String name, String prefix, int[] counts, SparseIntArray pidCounts) { 1232 String innerName = null; 1233 if (mObservers.size() > 0) { 1234 if ("".equals(name)) { 1235 innerName = mName; 1236 } else { 1237 innerName = name + "/" + mName; 1238 } 1239 for (int i=0; i<mObservers.size(); i++) { 1240 counts[1]++; 1241 mObservers.get(i).dumpLocked(fd, pw, args, innerName, prefix, 1242 pidCounts); 1243 } 1244 } 1245 if (mChildren.size() > 0) { 1246 if (innerName == null) { 1247 if ("".equals(name)) { 1248 innerName = mName; 1249 } else { 1250 innerName = name + "/" + mName; 1251 } 1252 } 1253 for (int i=0; i<mChildren.size(); i++) { 1254 counts[0]++; 1255 mChildren.get(i).dumpLocked(fd, pw, args, innerName, prefix, 1256 counts, pidCounts); 1257 } 1258 } 1259 } 1260 1261 private String getUriSegment(Uri uri, int index) { 1262 if (uri != null) { 1263 if (index == 0) { 1264 return uri.getAuthority(); 1265 } else { 1266 return uri.getPathSegments().get(index - 1); 1267 } 1268 } else { 1269 return null; 1270 } 1271 } 1272 1273 private int countUriSegments(Uri uri) { 1274 if (uri == null) { 1275 return 0; 1276 } 1277 return uri.getPathSegments().size() + 1; 1278 } 1279 1280 // Invariant: userHandle is either a hard user number or is USER_ALL 1281 public void addObserverLocked(Uri uri, IContentObserver observer, 1282 boolean notifyForDescendants, Object observersLock, 1283 int uid, int pid, int userHandle) { 1284 addObserverLocked(uri, 0, observer, notifyForDescendants, observersLock, 1285 uid, pid, userHandle); 1286 } 1287 1288 private void addObserverLocked(Uri uri, int index, IContentObserver observer, 1289 boolean notifyForDescendants, Object observersLock, 1290 int uid, int pid, int userHandle) { 1291 // If this is the leaf node add the observer 1292 if (index == countUriSegments(uri)) { 1293 mObservers.add(new ObserverEntry(observer, notifyForDescendants, observersLock, 1294 uid, pid, userHandle)); 1295 return; 1296 } 1297 1298 // Look to see if the proper child already exists 1299 String segment = getUriSegment(uri, index); 1300 if (segment == null) { 1301 throw new IllegalArgumentException("Invalid Uri (" + uri + ") used for observer"); 1302 } 1303 int N = mChildren.size(); 1304 for (int i = 0; i < N; i++) { 1305 ObserverNode node = mChildren.get(i); 1306 if (node.mName.equals(segment)) { 1307 node.addObserverLocked(uri, index + 1, observer, notifyForDescendants, 1308 observersLock, uid, pid, userHandle); 1309 return; 1310 } 1311 } 1312 1313 // No child found, create one 1314 ObserverNode node = new ObserverNode(segment); 1315 mChildren.add(node); 1316 node.addObserverLocked(uri, index + 1, observer, notifyForDescendants, 1317 observersLock, uid, pid, userHandle); 1318 } 1319 1320 public boolean removeObserverLocked(IContentObserver observer) { 1321 int size = mChildren.size(); 1322 for (int i = 0; i < size; i++) { 1323 boolean empty = mChildren.get(i).removeObserverLocked(observer); 1324 if (empty) { 1325 mChildren.remove(i); 1326 i--; 1327 size--; 1328 } 1329 } 1330 1331 IBinder observerBinder = observer.asBinder(); 1332 size = mObservers.size(); 1333 for (int i = 0; i < size; i++) { 1334 ObserverEntry entry = mObservers.get(i); 1335 if (entry.observer.asBinder() == observerBinder) { 1336 mObservers.remove(i); 1337 // We no longer need to listen for death notifications. Remove it. 1338 observerBinder.unlinkToDeath(entry, 0); 1339 break; 1340 } 1341 } 1342 1343 if (mChildren.size() == 0 && mObservers.size() == 0) { 1344 return true; 1345 } 1346 return false; 1347 } 1348 1349 private void collectMyObserversLocked(boolean leaf, IContentObserver observer, 1350 boolean observerWantsSelfNotifications, int flags, 1351 int targetUserHandle, ArrayList<ObserverCall> calls) { 1352 int N = mObservers.size(); 1353 IBinder observerBinder = observer == null ? null : observer.asBinder(); 1354 for (int i = 0; i < N; i++) { 1355 ObserverEntry entry = mObservers.get(i); 1356 1357 // Don't notify the observer if it sent the notification and isn't interested 1358 // in self notifications 1359 boolean selfChange = (entry.observer.asBinder() == observerBinder); 1360 if (selfChange && !observerWantsSelfNotifications) { 1361 continue; 1362 } 1363 1364 // Does this observer match the target user? 1365 if (targetUserHandle == UserHandle.USER_ALL 1366 || entry.userHandle == UserHandle.USER_ALL 1367 || targetUserHandle == entry.userHandle) { 1368 // Make sure the observer is interested in the notification 1369 if (leaf) { 1370 // If we are at the leaf: we always report, unless the sender has asked 1371 // to skip observers that are notifying for descendants (since they will 1372 // be sending another more specific URI for them). 1373 if ((flags&ContentResolver.NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS) != 0 1374 && entry.notifyForDescendants) { 1375 if (DEBUG) Slog.d(TAG, "Skipping " + entry.observer 1376 + ": skip notify for descendants"); 1377 continue; 1378 } 1379 } else { 1380 // If we are not at the leaf: we report if the observer says it wants 1381 // to be notified for all descendants. 1382 if (!entry.notifyForDescendants) { 1383 if (DEBUG) Slog.d(TAG, "Skipping " + entry.observer 1384 + ": not monitor descendants"); 1385 continue; 1386 } 1387 } 1388 if (DEBUG) Slog.d(TAG, "Reporting to " + entry.observer + ": leaf=" + leaf 1389 + " flags=" + Integer.toHexString(flags) 1390 + " desc=" + entry.notifyForDescendants); 1391 calls.add(new ObserverCall(this, entry.observer, selfChange, 1392 UserHandle.getUserId(entry.uid))); 1393 } 1394 } 1395 } 1396 1397 /** 1398 * targetUserHandle is either a hard user handle or is USER_ALL 1399 */ 1400 public void collectObserversLocked(Uri uri, int index, IContentObserver observer, 1401 boolean observerWantsSelfNotifications, int flags, 1402 int targetUserHandle, ArrayList<ObserverCall> calls) { 1403 String segment = null; 1404 int segmentCount = countUriSegments(uri); 1405 if (index >= segmentCount) { 1406 // This is the leaf node, notify all observers 1407 if (DEBUG) Slog.d(TAG, "Collecting leaf observers @ #" + index + ", node " + mName); 1408 collectMyObserversLocked(true, observer, observerWantsSelfNotifications, 1409 flags, targetUserHandle, calls); 1410 } else if (index < segmentCount){ 1411 segment = getUriSegment(uri, index); 1412 if (DEBUG) Slog.d(TAG, "Collecting non-leaf observers @ #" + index + " / " 1413 + segment); 1414 // Notify any observers at this level who are interested in descendants 1415 collectMyObserversLocked(false, observer, observerWantsSelfNotifications, 1416 flags, targetUserHandle, calls); 1417 } 1418 1419 int N = mChildren.size(); 1420 for (int i = 0; i < N; i++) { 1421 ObserverNode node = mChildren.get(i); 1422 if (segment == null || node.mName.equals(segment)) { 1423 // We found the child, 1424 node.collectObserversLocked(uri, index + 1, observer, 1425 observerWantsSelfNotifications, flags, targetUserHandle, calls); 1426 if (segment != null) { 1427 break; 1428 } 1429 } 1430 } 1431 } 1432 } 1433} 1434