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