1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.content; 18 19 import android.Manifest; 20 import android.accounts.Account; 21 import android.app.ActivityManager; 22 import android.content.ContentResolver; 23 import android.content.Context; 24 import android.content.IContentService; 25 import android.content.ISyncStatusObserver; 26 import android.content.PeriodicSync; 27 import android.content.SyncAdapterType; 28 import android.content.SyncInfo; 29 import android.content.SyncStatusInfo; 30 import android.database.IContentObserver; 31 import android.database.sqlite.SQLiteException; 32 import android.net.Uri; 33 import android.os.Binder; 34 import android.os.Bundle; 35 import android.os.IBinder; 36 import android.os.Parcel; 37 import android.os.RemoteException; 38 import android.os.ServiceManager; 39 import android.os.UserHandle; 40 import android.util.Log; 41 import android.util.Slog; 42 import android.util.SparseIntArray; 43 44 import java.io.FileDescriptor; 45 import java.io.PrintWriter; 46 import java.security.InvalidParameterException; 47 import java.util.ArrayList; 48 import java.util.Collections; 49 import java.util.Comparator; 50 import java.util.List; 51 52 /** 53 * {@hide} 54 */ 55 public final class ContentService extends IContentService.Stub { 56 private static final String TAG = "ContentService"; 57 private Context mContext; 58 private boolean mFactoryTest; 59 private final ObserverNode mRootNode = new ObserverNode(""); 60 private SyncManager mSyncManager = null; 61 private final Object mSyncManagerLock = new Object(); 62 63 private SyncManager getSyncManager() { 64 synchronized(mSyncManagerLock) { 65 try { 66 // Try to create the SyncManager, return null if it fails (e.g. the disk is full). 67 if (mSyncManager == null) mSyncManager = new SyncManager(mContext, mFactoryTest); 68 } catch (SQLiteException e) { 69 Log.e(TAG, "Can't create SyncManager", e); 70 } 71 return mSyncManager; 72 } 73 } 74 75 @Override 76 protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 77 mContext.enforceCallingOrSelfPermission(Manifest.permission.DUMP, 78 "caller doesn't have the DUMP permission"); 79 80 // This makes it so that future permission checks will be in the context of this 81 // process rather than the caller's process. We will restore this before returning. 82 long identityToken = clearCallingIdentity(); 83 try { 84 if (mSyncManager == null) { 85 pw.println("No SyncManager created! (Disk full?)"); 86 } else { 87 mSyncManager.dump(fd, pw); 88 } 89 pw.println(); 90 pw.println("Observer tree:"); 91 synchronized (mRootNode) { 92 int[] counts = new int[2]; 93 final SparseIntArray pidCounts = new SparseIntArray(); 94 mRootNode.dumpLocked(fd, pw, args, "", " ", counts, pidCounts); 95 pw.println(); 96 ArrayList<Integer> sorted = new ArrayList<Integer>(); 97 for (int i=0; i<pidCounts.size(); i++) { 98 sorted.add(pidCounts.keyAt(i)); 99 } 100 Collections.sort(sorted, new Comparator<Integer>() { 101 @Override 102 public int compare(Integer lhs, Integer rhs) { 103 int lc = pidCounts.get(lhs); 104 int rc = pidCounts.get(rhs); 105 if (lc < rc) { 106 return 1; 107 } else if (lc > rc) { 108 return -1; 109 } 110 return 0; 111 } 112 113 }); 114 for (int i=0; i<sorted.size(); i++) { 115 int pid = sorted.get(i); 116 pw.print(" pid "); pw.print(pid); pw.print(": "); 117 pw.print(pidCounts.get(pid)); pw.println(" observers"); 118 } 119 pw.println(); 120 pw.print(" Total number of nodes: "); pw.println(counts[0]); 121 pw.print(" Total number of observers: "); pw.println(counts[1]); 122 } 123 } finally { 124 restoreCallingIdentity(identityToken); 125 } 126 } 127 128 @Override 129 public boolean onTransact(int code, Parcel data, Parcel reply, int flags) 130 throws RemoteException { 131 try { 132 return super.onTransact(code, data, reply, flags); 133 } catch (RuntimeException e) { 134 // The content service only throws security exceptions, so let's 135 // log all others. 136 if (!(e instanceof SecurityException)) { 137 Log.e(TAG, "Content Service Crash", e); 138 } 139 throw e; 140 } 141 } 142 143 /*package*/ ContentService(Context context, boolean factoryTest) { 144 mContext = context; 145 mFactoryTest = factoryTest; 146 } 147 148 public void systemReady() { 149 getSyncManager(); 150 } 151 152 /** 153 * Register a content observer tied to a specific user's view of the provider. 154 * @param userHandle the user whose view of the provider is to be observed. May be 155 * the calling user without requiring any permission, otherwise the caller needs to 156 * hold the INTERACT_ACROSS_USERS_FULL permission. Pseudousers USER_ALL and 157 * USER_CURRENT are properly handled; all other pseudousers are forbidden. 158 */ 159 @Override 160 public void registerContentObserver(Uri uri, boolean notifyForDescendants, 161 IContentObserver observer, int userHandle) { 162 if (observer == null || uri == null) { 163 throw new IllegalArgumentException("You must pass a valid uri and observer"); 164 } 165 166 final int callingUser = UserHandle.getCallingUserId(); 167 if (callingUser != userHandle) { 168 mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, 169 "no permission to observe other users' provider view"); 170 } 171 172 if (userHandle < 0) { 173 if (userHandle == UserHandle.USER_CURRENT) { 174 userHandle = ActivityManager.getCurrentUser(); 175 } else if (userHandle != UserHandle.USER_ALL) { 176 throw new InvalidParameterException("Bad user handle for registerContentObserver: " 177 + userHandle); 178 } 179 } 180 181 synchronized (mRootNode) { 182 mRootNode.addObserverLocked(uri, observer, notifyForDescendants, mRootNode, 183 Binder.getCallingUid(), Binder.getCallingPid(), userHandle); 184 if (false) Log.v(TAG, "Registered observer " + observer + " at " + uri + 185 " with notifyForDescendants " + notifyForDescendants); 186 } 187 } 188 189 public void registerContentObserver(Uri uri, boolean notifyForDescendants, 190 IContentObserver observer) { 191 registerContentObserver(uri, notifyForDescendants, observer, 192 UserHandle.getCallingUserId()); 193 } 194 195 public void unregisterContentObserver(IContentObserver observer) { 196 if (observer == null) { 197 throw new IllegalArgumentException("You must pass a valid observer"); 198 } 199 synchronized (mRootNode) { 200 mRootNode.removeObserverLocked(observer); 201 if (false) Log.v(TAG, "Unregistered observer " + observer); 202 } 203 } 204 205 /** 206 * Notify observers of a particular user's view of the provider. 207 * @param userHandle the user whose view of the provider is to be notified. May be 208 * the calling user without requiring any permission, otherwise the caller needs to 209 * hold the INTERACT_ACROSS_USERS_FULL permission. Pseudousers USER_ALL and 210 * USER_CURRENT are properly interpreted; no other pseudousers are allowed. 211 */ 212 @Override 213 public void notifyChange(Uri uri, IContentObserver observer, 214 boolean observerWantsSelfNotifications, boolean syncToNetwork, 215 int userHandle) { 216 if (Log.isLoggable(TAG, Log.VERBOSE)) { 217 Log.v(TAG, "Notifying update of " + uri + " for user " + userHandle 218 + " from observer " + observer + ", syncToNetwork " + syncToNetwork); 219 } 220 221 // Notify for any user other than the caller's own requires permission. 222 final int callingUserHandle = UserHandle.getCallingUserId(); 223 if (userHandle != callingUserHandle) { 224 mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, 225 "no permission to notify other users"); 226 } 227 228 // We passed the permission check; resolve pseudouser targets as appropriate 229 if (userHandle < 0) { 230 if (userHandle == UserHandle.USER_CURRENT) { 231 userHandle = ActivityManager.getCurrentUser(); 232 } else if (userHandle != UserHandle.USER_ALL) { 233 throw new InvalidParameterException("Bad user handle for notifyChange: " 234 + userHandle); 235 } 236 } 237 238 final int uid = Binder.getCallingUid(); 239 // This makes it so that future permission checks will be in the context of this 240 // process rather than the caller's process. We will restore this before returning. 241 long identityToken = clearCallingIdentity(); 242 try { 243 ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>(); 244 synchronized (mRootNode) { 245 mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications, 246 userHandle, calls); 247 } 248 final int numCalls = calls.size(); 249 for (int i=0; i<numCalls; i++) { 250 ObserverCall oc = calls.get(i); 251 try { 252 oc.mObserver.onChange(oc.mSelfChange, uri); 253 if (Log.isLoggable(TAG, Log.VERBOSE)) { 254 Log.v(TAG, "Notified " + oc.mObserver + " of " + "update at " + uri); 255 } 256 } catch (RemoteException ex) { 257 synchronized (mRootNode) { 258 Log.w(TAG, "Found dead observer, removing"); 259 IBinder binder = oc.mObserver.asBinder(); 260 final ArrayList<ObserverNode.ObserverEntry> list 261 = oc.mNode.mObservers; 262 int numList = list.size(); 263 for (int j=0; j<numList; j++) { 264 ObserverNode.ObserverEntry oe = list.get(j); 265 if (oe.observer.asBinder() == binder) { 266 list.remove(j); 267 j--; 268 numList--; 269 } 270 } 271 } 272 } 273 } 274 if (syncToNetwork) { 275 SyncManager syncManager = getSyncManager(); 276 if (syncManager != null) { 277 syncManager.scheduleLocalSync(null /* all accounts */, callingUserHandle, uid, 278 uri.getAuthority()); 279 } 280 } 281 } finally { 282 restoreCallingIdentity(identityToken); 283 } 284 } 285 286 public void notifyChange(Uri uri, IContentObserver observer, 287 boolean observerWantsSelfNotifications, boolean syncToNetwork) { 288 notifyChange(uri, observer, observerWantsSelfNotifications, syncToNetwork, 289 UserHandle.getCallingUserId()); 290 } 291 292 /** 293 * Hide this class since it is not part of api, 294 * but current unittest framework requires it to be public 295 * @hide 296 * 297 */ 298 public static final class ObserverCall { 299 final ObserverNode mNode; 300 final IContentObserver mObserver; 301 final boolean mSelfChange; 302 303 ObserverCall(ObserverNode node, IContentObserver observer, boolean selfChange) { 304 mNode = node; 305 mObserver = observer; 306 mSelfChange = selfChange; 307 } 308 } 309 310 public void requestSync(Account account, String authority, Bundle extras) { 311 ContentResolver.validateSyncExtrasBundle(extras); 312 int userId = UserHandle.getCallingUserId(); 313 int uId = Binder.getCallingUid(); 314 315 // This makes it so that future permission checks will be in the context of this 316 // process rather than the caller's process. We will restore this before returning. 317 long identityToken = clearCallingIdentity(); 318 try { 319 SyncManager syncManager = getSyncManager(); 320 if (syncManager != null) { 321 syncManager.scheduleSync(account, userId, uId, authority, extras, 0 /* no delay */, 322 false /* onlyThoseWithUnkownSyncableState */); 323 } 324 } finally { 325 restoreCallingIdentity(identityToken); 326 } 327 } 328 329 /** 330 * Clear all scheduled sync operations that match the uri and cancel the active sync 331 * if they match the authority and account, if they are present. 332 * @param account filter the pending and active syncs to cancel using this account 333 * @param authority filter the pending and active syncs to cancel using this authority 334 */ 335 public void cancelSync(Account account, String authority) { 336 int userId = UserHandle.getCallingUserId(); 337 338 // This makes it so that future permission checks will be in the context of this 339 // process rather than the caller's process. We will restore this before returning. 340 long identityToken = clearCallingIdentity(); 341 try { 342 SyncManager syncManager = getSyncManager(); 343 if (syncManager != null) { 344 syncManager.clearScheduledSyncOperations(account, userId, authority); 345 syncManager.cancelActiveSync(account, userId, authority); 346 } 347 } finally { 348 restoreCallingIdentity(identityToken); 349 } 350 } 351 352 /** 353 * Get information about the SyncAdapters that are known to the system. 354 * @return an array of SyncAdapters that have registered with the system 355 */ 356 public SyncAdapterType[] getSyncAdapterTypes() { 357 // This makes it so that future permission checks will be in the context of this 358 // process rather than the caller's process. We will restore this before returning. 359 final int userId = UserHandle.getCallingUserId(); 360 final long identityToken = clearCallingIdentity(); 361 try { 362 SyncManager syncManager = getSyncManager(); 363 return syncManager.getSyncAdapterTypes(userId); 364 } finally { 365 restoreCallingIdentity(identityToken); 366 } 367 } 368 369 public boolean getSyncAutomatically(Account account, String providerName) { 370 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, 371 "no permission to read the sync settings"); 372 int userId = UserHandle.getCallingUserId(); 373 374 long identityToken = clearCallingIdentity(); 375 try { 376 SyncManager syncManager = getSyncManager(); 377 if (syncManager != null) { 378 return syncManager.getSyncStorageEngine().getSyncAutomatically( 379 account, userId, providerName); 380 } 381 } finally { 382 restoreCallingIdentity(identityToken); 383 } 384 return false; 385 } 386 387 public void setSyncAutomatically(Account account, String providerName, boolean sync) { 388 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, 389 "no permission to write the sync settings"); 390 int userId = UserHandle.getCallingUserId(); 391 392 long identityToken = clearCallingIdentity(); 393 try { 394 SyncManager syncManager = getSyncManager(); 395 if (syncManager != null) { 396 syncManager.getSyncStorageEngine().setSyncAutomatically( 397 account, userId, providerName, sync); 398 } 399 } finally { 400 restoreCallingIdentity(identityToken); 401 } 402 } 403 404 public void addPeriodicSync(Account account, String authority, Bundle extras, 405 long pollFrequency) { 406 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, 407 "no permission to write the sync settings"); 408 int userId = UserHandle.getCallingUserId(); 409 410 if (pollFrequency < 60) { 411 Slog.w(TAG, "Requested poll frequency of " + pollFrequency 412 + " seconds being rounded up to 60 seconds."); 413 pollFrequency = 60; 414 } 415 416 long identityToken = clearCallingIdentity(); 417 try { 418 getSyncManager().getSyncStorageEngine().addPeriodicSync( 419 account, userId, authority, extras, pollFrequency); 420 } finally { 421 restoreCallingIdentity(identityToken); 422 } 423 } 424 425 public void removePeriodicSync(Account account, String authority, Bundle extras) { 426 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, 427 "no permission to write the sync settings"); 428 int userId = UserHandle.getCallingUserId(); 429 430 long identityToken = clearCallingIdentity(); 431 try { 432 getSyncManager().getSyncStorageEngine().removePeriodicSync(account, userId, authority, 433 extras); 434 } finally { 435 restoreCallingIdentity(identityToken); 436 } 437 } 438 439 public List<PeriodicSync> getPeriodicSyncs(Account account, String providerName) { 440 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, 441 "no permission to read the sync settings"); 442 int userId = UserHandle.getCallingUserId(); 443 444 long identityToken = clearCallingIdentity(); 445 try { 446 return getSyncManager().getSyncStorageEngine().getPeriodicSyncs( 447 account, userId, providerName); 448 } finally { 449 restoreCallingIdentity(identityToken); 450 } 451 } 452 453 public int getIsSyncable(Account account, String providerName) { 454 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, 455 "no permission to read the sync settings"); 456 int userId = UserHandle.getCallingUserId(); 457 458 long identityToken = clearCallingIdentity(); 459 try { 460 SyncManager syncManager = getSyncManager(); 461 if (syncManager != null) { 462 return syncManager.getIsSyncable( 463 account, userId, providerName); 464 } 465 } finally { 466 restoreCallingIdentity(identityToken); 467 } 468 return -1; 469 } 470 471 public void setIsSyncable(Account account, String providerName, int syncable) { 472 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, 473 "no permission to write the sync settings"); 474 int userId = UserHandle.getCallingUserId(); 475 476 long identityToken = clearCallingIdentity(); 477 try { 478 SyncManager syncManager = getSyncManager(); 479 if (syncManager != null) { 480 syncManager.getSyncStorageEngine().setIsSyncable( 481 account, userId, providerName, syncable); 482 } 483 } finally { 484 restoreCallingIdentity(identityToken); 485 } 486 } 487 488 public boolean getMasterSyncAutomatically() { 489 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, 490 "no permission to read the sync settings"); 491 int userId = UserHandle.getCallingUserId(); 492 493 long identityToken = clearCallingIdentity(); 494 try { 495 SyncManager syncManager = getSyncManager(); 496 if (syncManager != null) { 497 return syncManager.getSyncStorageEngine().getMasterSyncAutomatically(userId); 498 } 499 } finally { 500 restoreCallingIdentity(identityToken); 501 } 502 return false; 503 } 504 505 public void setMasterSyncAutomatically(boolean flag) { 506 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, 507 "no permission to write the sync settings"); 508 int userId = UserHandle.getCallingUserId(); 509 510 long identityToken = clearCallingIdentity(); 511 try { 512 SyncManager syncManager = getSyncManager(); 513 if (syncManager != null) { 514 syncManager.getSyncStorageEngine().setMasterSyncAutomatically(flag, userId); 515 } 516 } finally { 517 restoreCallingIdentity(identityToken); 518 } 519 } 520 521 public boolean isSyncActive(Account account, String authority) { 522 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS, 523 "no permission to read the sync stats"); 524 int userId = UserHandle.getCallingUserId(); 525 526 long identityToken = clearCallingIdentity(); 527 try { 528 SyncManager syncManager = getSyncManager(); 529 if (syncManager != null) { 530 return syncManager.getSyncStorageEngine().isSyncActive( 531 account, userId, authority); 532 } 533 } finally { 534 restoreCallingIdentity(identityToken); 535 } 536 return false; 537 } 538 539 public List<SyncInfo> getCurrentSyncs() { 540 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS, 541 "no permission to read the sync stats"); 542 int userId = UserHandle.getCallingUserId(); 543 544 long identityToken = clearCallingIdentity(); 545 try { 546 return getSyncManager().getSyncStorageEngine().getCurrentSyncs(userId); 547 } finally { 548 restoreCallingIdentity(identityToken); 549 } 550 } 551 552 public SyncStatusInfo getSyncStatus(Account account, String authority) { 553 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS, 554 "no permission to read the sync stats"); 555 int userId = UserHandle.getCallingUserId(); 556 557 long identityToken = clearCallingIdentity(); 558 try { 559 SyncManager syncManager = getSyncManager(); 560 if (syncManager != null) { 561 return syncManager.getSyncStorageEngine().getStatusByAccountAndAuthority( 562 account, userId, authority); 563 } 564 } finally { 565 restoreCallingIdentity(identityToken); 566 } 567 return null; 568 } 569 570 public boolean isSyncPending(Account account, String authority) { 571 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS, 572 "no permission to read the sync stats"); 573 int userId = UserHandle.getCallingUserId(); 574 575 long identityToken = clearCallingIdentity(); 576 try { 577 SyncManager syncManager = getSyncManager(); 578 if (syncManager != null) { 579 return syncManager.getSyncStorageEngine().isSyncPending(account, userId, authority); 580 } 581 } finally { 582 restoreCallingIdentity(identityToken); 583 } 584 return false; 585 } 586 587 public void addStatusChangeListener(int mask, ISyncStatusObserver callback) { 588 long identityToken = clearCallingIdentity(); 589 try { 590 SyncManager syncManager = getSyncManager(); 591 if (syncManager != null && callback != null) { 592 syncManager.getSyncStorageEngine().addStatusChangeListener(mask, callback); 593 } 594 } finally { 595 restoreCallingIdentity(identityToken); 596 } 597 } 598 599 public void removeStatusChangeListener(ISyncStatusObserver callback) { 600 long identityToken = clearCallingIdentity(); 601 try { 602 SyncManager syncManager = getSyncManager(); 603 if (syncManager != null && callback != null) { 604 syncManager.getSyncStorageEngine().removeStatusChangeListener(callback); 605 } 606 } finally { 607 restoreCallingIdentity(identityToken); 608 } 609 } 610 611 public static ContentService main(Context context, boolean factoryTest) { 612 ContentService service = new ContentService(context, factoryTest); 613 ServiceManager.addService(ContentResolver.CONTENT_SERVICE_NAME, service); 614 return service; 615 } 616 617 /** 618 * Hide this class since it is not part of api, 619 * but current unittest framework requires it to be public 620 * @hide 621 */ 622 public static final class ObserverNode { 623 private class ObserverEntry implements IBinder.DeathRecipient { 624 public final IContentObserver observer; 625 public final int uid; 626 public final int pid; 627 public final boolean notifyForDescendants; 628 private final int userHandle; 629 private final Object observersLock; 630 631 public ObserverEntry(IContentObserver o, boolean n, Object observersLock, 632 int _uid, int _pid, int _userHandle) { 633 this.observersLock = observersLock; 634 observer = o; 635 uid = _uid; 636 pid = _pid; 637 userHandle = _userHandle; 638 notifyForDescendants = n; 639 try { 640 observer.asBinder().linkToDeath(this, 0); 641 } catch (RemoteException e) { 642 binderDied(); 643 } 644 } 645 646 public void binderDied() { 647 synchronized (observersLock) { 648 removeObserverLocked(observer); 649 } 650 } 651 652 public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args, 653 String name, String prefix, SparseIntArray pidCounts) { 654 pidCounts.put(pid, pidCounts.get(pid)+1); 655 pw.print(prefix); pw.print(name); pw.print(": pid="); 656 pw.print(pid); pw.print(" uid="); 657 pw.print(uid); pw.print(" user="); 658 pw.print(userHandle); pw.print(" target="); 659 pw.println(Integer.toHexString(System.identityHashCode( 660 observer != null ? observer.asBinder() : null))); 661 } 662 } 663 664 public static final int INSERT_TYPE = 0; 665 public static final int UPDATE_TYPE = 1; 666 public static final int DELETE_TYPE = 2; 667 668 private String mName; 669 private ArrayList<ObserverNode> mChildren = new ArrayList<ObserverNode>(); 670 private ArrayList<ObserverEntry> mObservers = new ArrayList<ObserverEntry>(); 671 672 public ObserverNode(String name) { 673 mName = name; 674 } 675 676 public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args, 677 String name, String prefix, int[] counts, SparseIntArray pidCounts) { 678 String innerName = null; 679 if (mObservers.size() > 0) { 680 if ("".equals(name)) { 681 innerName = mName; 682 } else { 683 innerName = name + "/" + mName; 684 } 685 for (int i=0; i<mObservers.size(); i++) { 686 counts[1]++; 687 mObservers.get(i).dumpLocked(fd, pw, args, innerName, prefix, 688 pidCounts); 689 } 690 } 691 if (mChildren.size() > 0) { 692 if (innerName == null) { 693 if ("".equals(name)) { 694 innerName = mName; 695 } else { 696 innerName = name + "/" + mName; 697 } 698 } 699 for (int i=0; i<mChildren.size(); i++) { 700 counts[0]++; 701 mChildren.get(i).dumpLocked(fd, pw, args, innerName, prefix, 702 counts, pidCounts); 703 } 704 } 705 } 706 707 private String getUriSegment(Uri uri, int index) { 708 if (uri != null) { 709 if (index == 0) { 710 return uri.getAuthority(); 711 } else { 712 return uri.getPathSegments().get(index - 1); 713 } 714 } else { 715 return null; 716 } 717 } 718 719 private int countUriSegments(Uri uri) { 720 if (uri == null) { 721 return 0; 722 } 723 return uri.getPathSegments().size() + 1; 724 } 725 726 // Invariant: userHandle is either a hard user number or is USER_ALL 727 public void addObserverLocked(Uri uri, IContentObserver observer, 728 boolean notifyForDescendants, Object observersLock, 729 int uid, int pid, int userHandle) { 730 addObserverLocked(uri, 0, observer, notifyForDescendants, observersLock, 731 uid, pid, userHandle); 732 } 733 734 private void addObserverLocked(Uri uri, int index, IContentObserver observer, 735 boolean notifyForDescendants, Object observersLock, 736 int uid, int pid, int userHandle) { 737 // If this is the leaf node add the observer 738 if (index == countUriSegments(uri)) { 739 mObservers.add(new ObserverEntry(observer, notifyForDescendants, observersLock, 740 uid, pid, userHandle)); 741 return; 742 } 743 744 // Look to see if the proper child already exists 745 String segment = getUriSegment(uri, index); 746 if (segment == null) { 747 throw new IllegalArgumentException("Invalid Uri (" + uri + ") used for observer"); 748 } 749 int N = mChildren.size(); 750 for (int i = 0; i < N; i++) { 751 ObserverNode node = mChildren.get(i); 752 if (node.mName.equals(segment)) { 753 node.addObserverLocked(uri, index + 1, observer, notifyForDescendants, 754 observersLock, uid, pid, userHandle); 755 return; 756 } 757 } 758 759 // No child found, create one 760 ObserverNode node = new ObserverNode(segment); 761 mChildren.add(node); 762 node.addObserverLocked(uri, index + 1, observer, notifyForDescendants, 763 observersLock, uid, pid, userHandle); 764 } 765 766 public boolean removeObserverLocked(IContentObserver observer) { 767 int size = mChildren.size(); 768 for (int i = 0; i < size; i++) { 769 boolean empty = mChildren.get(i).removeObserverLocked(observer); 770 if (empty) { 771 mChildren.remove(i); 772 i--; 773 size--; 774 } 775 } 776 777 IBinder observerBinder = observer.asBinder(); 778 size = mObservers.size(); 779 for (int i = 0; i < size; i++) { 780 ObserverEntry entry = mObservers.get(i); 781 if (entry.observer.asBinder() == observerBinder) { 782 mObservers.remove(i); 783 // We no longer need to listen for death notifications. Remove it. 784 observerBinder.unlinkToDeath(entry, 0); 785 break; 786 } 787 } 788 789 if (mChildren.size() == 0 && mObservers.size() == 0) { 790 return true; 791 } 792 return false; 793 } 794 795 private void collectMyObserversLocked(boolean leaf, IContentObserver observer, 796 boolean observerWantsSelfNotifications, int targetUserHandle, 797 ArrayList<ObserverCall> calls) { 798 int N = mObservers.size(); 799 IBinder observerBinder = observer == null ? null : observer.asBinder(); 800 for (int i = 0; i < N; i++) { 801 ObserverEntry entry = mObservers.get(i); 802 803 // Don't notify the observer if it sent the notification and isn't interested 804 // in self notifications 805 boolean selfChange = (entry.observer.asBinder() == observerBinder); 806 if (selfChange && !observerWantsSelfNotifications) { 807 continue; 808 } 809 810 // Does this observer match the target user? 811 if (targetUserHandle == UserHandle.USER_ALL 812 || entry.userHandle == UserHandle.USER_ALL 813 || targetUserHandle == entry.userHandle) { 814 // Make sure the observer is interested in the notification 815 if (leaf || (!leaf && entry.notifyForDescendants)) { 816 calls.add(new ObserverCall(this, entry.observer, selfChange)); 817 } 818 } 819 } 820 } 821 822 /** 823 * targetUserHandle is either a hard user handle or is USER_ALL 824 */ 825 public void collectObserversLocked(Uri uri, int index, IContentObserver observer, 826 boolean observerWantsSelfNotifications, int targetUserHandle, 827 ArrayList<ObserverCall> calls) { 828 String segment = null; 829 int segmentCount = countUriSegments(uri); 830 if (index >= segmentCount) { 831 // This is the leaf node, notify all observers 832 collectMyObserversLocked(true, observer, observerWantsSelfNotifications, 833 targetUserHandle, calls); 834 } else if (index < segmentCount){ 835 segment = getUriSegment(uri, index); 836 // Notify any observers at this level who are interested in descendants 837 collectMyObserversLocked(false, observer, observerWantsSelfNotifications, 838 targetUserHandle, calls); 839 } 840 841 int N = mChildren.size(); 842 for (int i = 0; i < N; i++) { 843 ObserverNode node = mChildren.get(i); 844 if (segment == null || node.mName.equals(segment)) { 845 // We found the child, 846 node.collectObserversLocked(uri, index + 1, 847 observer, observerWantsSelfNotifications, targetUserHandle, calls); 848 if (segment != null) { 849 break; 850 } 851 } 852 } 853 } 854 } 855 } 856