2 * Copyright (C) 2006 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server.content;
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.SparseIntArray;
43 import java.io.FileDescriptor;
44 import java.io.PrintWriter;
45 import java.security.InvalidParameterException;
46 import java.util.ArrayList;
47 import java.util.Collections;
48 import java.util.Comparator;
49 import java.util.List;
54 public final class ContentService extends IContentService.Stub {
55 private static final String TAG = "ContentService";
56 private Context mContext;
57 private boolean mFactoryTest;
58 private final ObserverNode mRootNode = new ObserverNode("");
59 private SyncManager mSyncManager = null;
60 private final Object mSyncManagerLock = new Object();
62 private SyncManager getSyncManager() {
63 synchronized(mSyncManagerLock) {
65 // Try to create the SyncManager, return null if it fails (e.g. the disk is full).
66 if (mSyncManager == null) mSyncManager = new SyncManager(mContext, mFactoryTest);
67 } catch (SQLiteException e) {
68 Log.e(TAG, "Can't create SyncManager", e);
75 protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
76 mContext.enforceCallingOrSelfPermission(Manifest.permission.DUMP,
77 "caller doesn't have the DUMP permission");
79 // This makes it so that future permission checks will be in the context of this
80 // process rather than the caller's process. We will restore this before returning.
81 long identityToken = clearCallingIdentity();
83 if (mSyncManager == null) {
84 pw.println("No SyncManager created! (Disk full?)");
86 mSyncManager.dump(fd, pw);
89 pw.println("Observer tree:");
90 synchronized (mRootNode) {
91 int[] counts = new int[2];
92 final SparseIntArray pidCounts = new SparseIntArray();
93 mRootNode.dumpLocked(fd, pw, args, "", " ", counts, pidCounts);
95 ArrayList<Integer> sorted = new ArrayList<Integer>();
96 for (int i=0; i<pidCounts.size(); i++) {
97 sorted.add(pidCounts.keyAt(i));
99 Collections.sort(sorted, new Comparator<Integer>() {
101 public int compare(Integer lhs, Integer rhs) {
102 int lc = pidCounts.get(lhs);
103 int rc = pidCounts.get(rhs);
106 } else if (lc > rc) {
113 for (int i=0; i<sorted.size(); i++) {
114 int pid = sorted.get(i);
115 pw.print(" pid "); pw.print(pid); pw.print(": ");
116 pw.print(pidCounts.get(pid)); pw.println(" observers");
119 pw.print(" Total number of nodes: "); pw.println(counts[0]);
120 pw.print(" Total number of observers: "); pw.println(counts[1]);
123 restoreCallingIdentity(identityToken);
128 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
129 throws RemoteException {
131 return super.onTransact(code, data, reply, flags);
132 } catch (RuntimeException e) {
133 // The content service only throws security exceptions, so let's
135 if (!(e instanceof SecurityException)) {
136 Log.e(TAG, "Content Service Crash", e);
142 /*package*/ ContentService(Context context, boolean factoryTest) {
144 mFactoryTest = factoryTest;
147 public void systemReady() {
152 * Register a content observer tied to a specific user's view of the provider.
153 * @param userHandle the user whose view of the provider is to be observed. May be
154 * the calling user without requiring any permission, otherwise the caller needs to
155 * hold the INTERACT_ACROSS_USERS_FULL permission. Pseudousers USER_ALL and
156 * USER_CURRENT are properly handled; all other pseudousers are forbidden.
159 public void registerContentObserver(Uri uri, boolean notifyForDescendants,
160 IContentObserver observer, int userHandle) {
161 if (observer == null || uri == null) {
162 throw new IllegalArgumentException("You must pass a valid uri and observer");
165 final int callingUser = UserHandle.getCallingUserId();
166 if (callingUser != userHandle) {
167 mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
168 "no permission to observe other users' provider view");
171 if (userHandle < 0) {
172 if (userHandle == UserHandle.USER_CURRENT) {
173 userHandle = ActivityManager.getCurrentUser();
174 } else if (userHandle != UserHandle.USER_ALL) {
175 throw new InvalidParameterException("Bad user handle for registerContentObserver: "
180 synchronized (mRootNode) {
181 mRootNode.addObserverLocked(uri, observer, notifyForDescendants, mRootNode,
182 Binder.getCallingUid(), Binder.getCallingPid(), userHandle);
183 if (false) Log.v(TAG, "Registered observer " + observer + " at " + uri +
184 " with notifyForDescendants " + notifyForDescendants);
188 public void registerContentObserver(Uri uri, boolean notifyForDescendants,
189 IContentObserver observer) {
190 registerContentObserver(uri, notifyForDescendants, observer,
191 UserHandle.getCallingUserId());
194 public void unregisterContentObserver(IContentObserver observer) {
195 if (observer == null) {
196 throw new IllegalArgumentException("You must pass a valid observer");
198 synchronized (mRootNode) {
199 mRootNode.removeObserverLocked(observer);
200 if (false) Log.v(TAG, "Unregistered observer " + observer);
205 * Notify observers of a particular user's view of the provider.
206 * @param userHandle the user whose view of the provider is to be notified. May be
207 * the calling user without requiring any permission, otherwise the caller needs to
208 * hold the INTERACT_ACROSS_USERS_FULL permission. Pseudousers USER_ALL and
209 * USER_CURRENT are properly interpreted; no other pseudousers are allowed.
212 public void notifyChange(Uri uri, IContentObserver observer,
213 boolean observerWantsSelfNotifications, boolean syncToNetwork,
215 if (Log.isLoggable(TAG, Log.VERBOSE)) {
216 Log.v(TAG, "Notifying update of " + uri + " for user " + userHandle
217 + " from observer " + observer + ", syncToNetwork " + syncToNetwork);
220 // Notify for any user other than the caller's own requires permission.
221 final int callingUserHandle = UserHandle.getCallingUserId();
222 if (userHandle != callingUserHandle) {
223 mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
224 "no permission to notify other users");
227 // We passed the permission check; resolve pseudouser targets as appropriate
228 if (userHandle < 0) {
229 if (userHandle == UserHandle.USER_CURRENT) {
230 userHandle = ActivityManager.getCurrentUser();
231 } else if (userHandle != UserHandle.USER_ALL) {
232 throw new InvalidParameterException("Bad user handle for notifyChange: "
237 final int uid = Binder.getCallingUid();
238 // This makes it so that future permission checks will be in the context of this
239 // process rather than the caller's process. We will restore this before returning.
240 long identityToken = clearCallingIdentity();
242 ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
243 synchronized (mRootNode) {
244 mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications,
247 final int numCalls = calls.size();
248 for (int i=0; i<numCalls; i++) {
249 ObserverCall oc = calls.get(i);
251 oc.mObserver.onChange(oc.mSelfChange, uri);
252 if (Log.isLoggable(TAG, Log.VERBOSE)) {
253 Log.v(TAG, "Notified " + oc.mObserver + " of " + "update at " + uri);
255 } catch (RemoteException ex) {
256 synchronized (mRootNode) {
257 Log.w(TAG, "Found dead observer, removing");
258 IBinder binder = oc.mObserver.asBinder();
259 final ArrayList<ObserverNode.ObserverEntry> list
260 = oc.mNode.mObservers;
261 int numList = list.size();
262 for (int j=0; j<numList; j++) {
263 ObserverNode.ObserverEntry oe = list.get(j);
264 if (oe.observer.asBinder() == binder) {
274 SyncManager syncManager = getSyncManager();
275 if (syncManager != null) {
276 syncManager.scheduleLocalSync(null /* all accounts */, callingUserHandle, uid,
281 restoreCallingIdentity(identityToken);
285 public void notifyChange(Uri uri, IContentObserver observer,
286 boolean observerWantsSelfNotifications, boolean syncToNetwork) {
287 notifyChange(uri, observer, observerWantsSelfNotifications, syncToNetwork,
288 UserHandle.getCallingUserId());
292 * Hide this class since it is not part of api,
293 * but current unittest framework requires it to be public
297 public static final class ObserverCall {
298 final ObserverNode mNode;
299 final IContentObserver mObserver;
300 final boolean mSelfChange;
302 ObserverCall(ObserverNode node, IContentObserver observer, boolean selfChange) {
304 mObserver = observer;
305 mSelfChange = selfChange;
309 public void requestSync(Account account, String authority, Bundle extras) {
310 ContentResolver.validateSyncExtrasBundle(extras);
311 int userId = UserHandle.getCallingUserId();
312 int uId = Binder.getCallingUid();
314 // This makes it so that future permission checks will be in the context of this
315 // process rather than the caller's process. We will restore this before returning.
316 long identityToken = clearCallingIdentity();
318 SyncManager syncManager = getSyncManager();
319 if (syncManager != null) {
320 syncManager.scheduleSync(account, userId, uId, authority, extras, 0 /* no delay */,
321 false /* onlyThoseWithUnkownSyncableState */);
324 restoreCallingIdentity(identityToken);
329 * Clear all scheduled sync operations that match the uri and cancel the active sync
330 * if they match the authority and account, if they are present.
331 * @param account filter the pending and active syncs to cancel using this account
332 * @param authority filter the pending and active syncs to cancel using this authority
334 public void cancelSync(Account account, String authority) {
335 int userId = UserHandle.getCallingUserId();
337 // This makes it so that future permission checks will be in the context of this
338 // process rather than the caller's process. We will restore this before returning.
339 long identityToken = clearCallingIdentity();
341 SyncManager syncManager = getSyncManager();
342 if (syncManager != null) {
343 syncManager.clearScheduledSyncOperations(account, userId, authority);
344 syncManager.cancelActiveSync(account, userId, authority);
347 restoreCallingIdentity(identityToken);
352 * Get information about the SyncAdapters that are known to the system.
353 * @return an array of SyncAdapters that have registered with the system
355 public SyncAdapterType[] getSyncAdapterTypes() {
356 // This makes it so that future permission checks will be in the context of this
357 // process rather than the caller's process. We will restore this before returning.
358 final int userId = UserHandle.getCallingUserId();
359 final long identityToken = clearCallingIdentity();
361 SyncManager syncManager = getSyncManager();
362 return syncManager.getSyncAdapterTypes(userId);
364 restoreCallingIdentity(identityToken);
368 public boolean getSyncAutomatically(Account account, String providerName) {
369 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
370 "no permission to read the sync settings");
371 int userId = UserHandle.getCallingUserId();
373 long identityToken = clearCallingIdentity();
375 SyncManager syncManager = getSyncManager();
376 if (syncManager != null) {
377 return syncManager.getSyncStorageEngine().getSyncAutomatically(
378 account, userId, providerName);
381 restoreCallingIdentity(identityToken);
386 public void setSyncAutomatically(Account account, String providerName, boolean sync) {
387 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
388 "no permission to write the sync settings");
389 int userId = UserHandle.getCallingUserId();
391 long identityToken = clearCallingIdentity();
393 SyncManager syncManager = getSyncManager();
394 if (syncManager != null) {
395 syncManager.getSyncStorageEngine().setSyncAutomatically(
396 account, userId, providerName, sync);
399 restoreCallingIdentity(identityToken);
403 public void addPeriodicSync(Account account, String authority, Bundle extras,
404 long pollFrequency) {
405 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
406 "no permission to write the sync settings");
407 int userId = UserHandle.getCallingUserId();
409 long identityToken = clearCallingIdentity();
411 getSyncManager().getSyncStorageEngine().addPeriodicSync(
412 account, userId, authority, extras, pollFrequency);
414 restoreCallingIdentity(identityToken);
418 public void removePeriodicSync(Account account, String authority, Bundle extras) {
419 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
420 "no permission to write the sync settings");
421 int userId = UserHandle.getCallingUserId();
423 long identityToken = clearCallingIdentity();
425 getSyncManager().getSyncStorageEngine().removePeriodicSync(account, userId, authority,
428 restoreCallingIdentity(identityToken);
432 public List<PeriodicSync> getPeriodicSyncs(Account account, String providerName) {
433 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
434 "no permission to read the sync settings");
435 int userId = UserHandle.getCallingUserId();
437 long identityToken = clearCallingIdentity();
439 return getSyncManager().getSyncStorageEngine().getPeriodicSyncs(
440 account, userId, providerName);
442 restoreCallingIdentity(identityToken);
446 public int getIsSyncable(Account account, String providerName) {
447 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
448 "no permission to read the sync settings");
449 int userId = UserHandle.getCallingUserId();
451 long identityToken = clearCallingIdentity();
453 SyncManager syncManager = getSyncManager();
454 if (syncManager != null) {
455 return syncManager.getSyncStorageEngine().getIsSyncable(
456 account, userId, providerName);
459 restoreCallingIdentity(identityToken);
464 public void setIsSyncable(Account account, String providerName, int syncable) {
465 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
466 "no permission to write the sync settings");
467 int userId = UserHandle.getCallingUserId();
469 long identityToken = clearCallingIdentity();
471 SyncManager syncManager = getSyncManager();
472 if (syncManager != null) {
473 syncManager.getSyncStorageEngine().setIsSyncable(
474 account, userId, providerName, syncable);
477 restoreCallingIdentity(identityToken);
481 public boolean getMasterSyncAutomatically() {
482 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
483 "no permission to read the sync settings");
484 int userId = UserHandle.getCallingUserId();
486 long identityToken = clearCallingIdentity();
488 SyncManager syncManager = getSyncManager();
489 if (syncManager != null) {
490 return syncManager.getSyncStorageEngine().getMasterSyncAutomatically(userId);
493 restoreCallingIdentity(identityToken);
498 public void setMasterSyncAutomatically(boolean flag) {
499 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
500 "no permission to write the sync settings");
501 int userId = UserHandle.getCallingUserId();
503 long identityToken = clearCallingIdentity();
505 SyncManager syncManager = getSyncManager();
506 if (syncManager != null) {
507 syncManager.getSyncStorageEngine().setMasterSyncAutomatically(flag, userId);
510 restoreCallingIdentity(identityToken);
514 public boolean isSyncActive(Account account, String authority) {
515 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
516 "no permission to read the sync stats");
517 int userId = UserHandle.getCallingUserId();
519 long identityToken = clearCallingIdentity();
521 SyncManager syncManager = getSyncManager();
522 if (syncManager != null) {
523 return syncManager.getSyncStorageEngine().isSyncActive(
524 account, userId, authority);
527 restoreCallingIdentity(identityToken);
532 public List<SyncInfo> getCurrentSyncs() {
533 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
534 "no permission to read the sync stats");
535 int userId = UserHandle.getCallingUserId();
537 long identityToken = clearCallingIdentity();
539 return getSyncManager().getSyncStorageEngine().getCurrentSyncs(userId);
541 restoreCallingIdentity(identityToken);
545 public SyncStatusInfo getSyncStatus(Account account, String authority) {
546 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
547 "no permission to read the sync stats");
548 int userId = UserHandle.getCallingUserId();
550 long identityToken = clearCallingIdentity();
552 SyncManager syncManager = getSyncManager();
553 if (syncManager != null) {
554 return syncManager.getSyncStorageEngine().getStatusByAccountAndAuthority(
555 account, userId, authority);
558 restoreCallingIdentity(identityToken);
563 public boolean isSyncPending(Account account, String authority) {
564 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
565 "no permission to read the sync stats");
566 int userId = UserHandle.getCallingUserId();
568 long identityToken = clearCallingIdentity();
570 SyncManager syncManager = getSyncManager();
571 if (syncManager != null) {
572 return syncManager.getSyncStorageEngine().isSyncPending(account, userId, authority);
575 restoreCallingIdentity(identityToken);
580 public void addStatusChangeListener(int mask, ISyncStatusObserver callback) {
581 long identityToken = clearCallingIdentity();
583 SyncManager syncManager = getSyncManager();
584 if (syncManager != null && callback != null) {
585 syncManager.getSyncStorageEngine().addStatusChangeListener(mask, callback);
588 restoreCallingIdentity(identityToken);
592 public void removeStatusChangeListener(ISyncStatusObserver callback) {
593 long identityToken = clearCallingIdentity();
595 SyncManager syncManager = getSyncManager();
596 if (syncManager != null && callback != null) {
597 syncManager.getSyncStorageEngine().removeStatusChangeListener(callback);
600 restoreCallingIdentity(identityToken);
604 public static ContentService main(Context context, boolean factoryTest) {
605 ContentService service = new ContentService(context, factoryTest);
606 ServiceManager.addService(ContentResolver.CONTENT_SERVICE_NAME, service);
611 * Hide this class since it is not part of api,
612 * but current unittest framework requires it to be public
615 public static final class ObserverNode {
616 private class ObserverEntry implements IBinder.DeathRecipient {
617 public final IContentObserver observer;
618 public final int uid;
619 public final int pid;
620 public final boolean notifyForDescendants;
621 private final int userHandle;
622 private final Object observersLock;
624 public ObserverEntry(IContentObserver o, boolean n, Object observersLock,
625 int _uid, int _pid, int _userHandle) {
626 this.observersLock = observersLock;
630 userHandle = _userHandle;
631 notifyForDescendants = n;
633 observer.asBinder().linkToDeath(this, 0);
634 } catch (RemoteException e) {
639 public void binderDied() {
640 synchronized (observersLock) {
641 removeObserverLocked(observer);
645 public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
646 String name, String prefix, SparseIntArray pidCounts) {
647 pidCounts.put(pid, pidCounts.get(pid)+1);
648 pw.print(prefix); pw.print(name); pw.print(": pid=");
649 pw.print(pid); pw.print(" uid=");
650 pw.print(uid); pw.print(" user=");
651 pw.print(userHandle); pw.print(" target=");
652 pw.println(Integer.toHexString(System.identityHashCode(
653 observer != null ? observer.asBinder() : null)));
657 public static final int INSERT_TYPE = 0;
658 public static final int UPDATE_TYPE = 1;
659 public static final int DELETE_TYPE = 2;
661 private String mName;
662 private ArrayList<ObserverNode> mChildren = new ArrayList<ObserverNode>();
663 private ArrayList<ObserverEntry> mObservers = new ArrayList<ObserverEntry>();
665 public ObserverNode(String name) {
669 public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
670 String name, String prefix, int[] counts, SparseIntArray pidCounts) {
671 String innerName = null;
672 if (mObservers.size() > 0) {
673 if ("".equals(name)) {
676 innerName = name + "/" + mName;
678 for (int i=0; i<mObservers.size(); i++) {
680 mObservers.get(i).dumpLocked(fd, pw, args, innerName, prefix,
684 if (mChildren.size() > 0) {
685 if (innerName == null) {
686 if ("".equals(name)) {
689 innerName = name + "/" + mName;
692 for (int i=0; i<mChildren.size(); i++) {
694 mChildren.get(i).dumpLocked(fd, pw, args, innerName, prefix,
700 private String getUriSegment(Uri uri, int index) {
703 return uri.getAuthority();
705 return uri.getPathSegments().get(index - 1);
712 private int countUriSegments(Uri uri) {
716 return uri.getPathSegments().size() + 1;
719 // Invariant: userHandle is either a hard user number or is USER_ALL
720 public void addObserverLocked(Uri uri, IContentObserver observer,
721 boolean notifyForDescendants, Object observersLock,
722 int uid, int pid, int userHandle) {
723 addObserverLocked(uri, 0, observer, notifyForDescendants, observersLock,
724 uid, pid, userHandle);
727 private void addObserverLocked(Uri uri, int index, IContentObserver observer,
728 boolean notifyForDescendants, Object observersLock,
729 int uid, int pid, int userHandle) {
730 // If this is the leaf node add the observer
731 if (index == countUriSegments(uri)) {
732 mObservers.add(new ObserverEntry(observer, notifyForDescendants, observersLock,
733 uid, pid, userHandle));
737 // Look to see if the proper child already exists
738 String segment = getUriSegment(uri, index);
739 if (segment == null) {
740 throw new IllegalArgumentException("Invalid Uri (" + uri + ") used for observer");
742 int N = mChildren.size();
743 for (int i = 0; i < N; i++) {
744 ObserverNode node = mChildren.get(i);
745 if (node.mName.equals(segment)) {
746 node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,
747 observersLock, uid, pid, userHandle);
752 // No child found, create one
753 ObserverNode node = new ObserverNode(segment);
755 node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,
756 observersLock, uid, pid, userHandle);
759 public boolean removeObserverLocked(IContentObserver observer) {
760 int size = mChildren.size();
761 for (int i = 0; i < size; i++) {
762 boolean empty = mChildren.get(i).removeObserverLocked(observer);
770 IBinder observerBinder = observer.asBinder();
771 size = mObservers.size();
772 for (int i = 0; i < size; i++) {
773 ObserverEntry entry = mObservers.get(i);
774 if (entry.observer.asBinder() == observerBinder) {
775 mObservers.remove(i);
776 // We no longer need to listen for death notifications. Remove it.
777 observerBinder.unlinkToDeath(entry, 0);
782 if (mChildren.size() == 0 && mObservers.size() == 0) {
788 private void collectMyObserversLocked(boolean leaf, IContentObserver observer,
789 boolean observerWantsSelfNotifications, int targetUserHandle,
790 ArrayList<ObserverCall> calls) {
791 int N = mObservers.size();
792 IBinder observerBinder = observer == null ? null : observer.asBinder();
793 for (int i = 0; i < N; i++) {
794 ObserverEntry entry = mObservers.get(i);
796 // Don't notify the observer if it sent the notification and isn't interested
797 // in self notifications
798 boolean selfChange = (entry.observer.asBinder() == observerBinder);
799 if (selfChange && !observerWantsSelfNotifications) {
803 // Does this observer match the target user?
804 if (targetUserHandle == UserHandle.USER_ALL
805 || entry.userHandle == UserHandle.USER_ALL
806 || targetUserHandle == entry.userHandle) {
807 // Make sure the observer is interested in the notification
808 if (leaf || (!leaf && entry.notifyForDescendants)) {
809 calls.add(new ObserverCall(this, entry.observer, selfChange));
816 * targetUserHandle is either a hard user handle or is USER_ALL
818 public void collectObserversLocked(Uri uri, int index, IContentObserver observer,
819 boolean observerWantsSelfNotifications, int targetUserHandle,
820 ArrayList<ObserverCall> calls) {
821 String segment = null;
822 int segmentCount = countUriSegments(uri);
823 if (index >= segmentCount) {
824 // This is the leaf node, notify all observers
825 collectMyObserversLocked(true, observer, observerWantsSelfNotifications,
826 targetUserHandle, calls);
827 } else if (index < segmentCount){
828 segment = getUriSegment(uri, index);
829 // Notify any observers at this level who are interested in descendants
830 collectMyObserversLocked(false, observer, observerWantsSelfNotifications,
831 targetUserHandle, calls);
834 int N = mChildren.size();
835 for (int i = 0; i < N; i++) {
836 ObserverNode node = mChildren.get(i);
837 if (segment == null || node.mName.equals(segment)) {
838 // We found the child,
839 node.collectObserversLocked(uri, index + 1,
840 observer, observerWantsSelfNotifications, targetUserHandle, calls);
841 if (segment != null) {